summaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/ath/ath9k/xmit.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c354
1 files changed, 216 insertions, 138 deletions
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index 42551a4..564c6cb 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -70,6 +70,29 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf,
static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
int nbad, int txok, bool update_rc);
+enum {
+ MCS_DEFAULT,
+ MCS_HT40,
+ MCS_HT40_SGI,
+};
+
+static int ath_max_4ms_framelen[3][16] = {
+ [MCS_DEFAULT] = {
+ 3216, 6434, 9650, 12868, 19304, 25740, 28956, 32180,
+ 6430, 12860, 19300, 25736, 38600, 51472, 57890, 64320,
+ },
+ [MCS_HT40] = {
+ 6684, 13368, 20052, 26738, 40104, 53476, 60156, 66840,
+ 13360, 26720, 40080, 53440, 80160, 106880, 120240, 133600,
+ },
+ [MCS_HT40_SGI] = {
+ /* TODO: Only MCS 7 and 15 updated, recalculate the rest */
+ 6684, 13368, 20052, 26738, 40104, 53476, 60156, 74200,
+ 13360, 26720, 40080, 53440, 80160, 106880, 120240, 148400,
+ }
+};
+
+
/*********************/
/* Aggregation logic */
/*********************/
@@ -107,7 +130,7 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
{
struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
- ASSERT(tid->paused > 0);
+ BUG_ON(tid->paused <= 0);
spin_lock_bh(&txq->axq_lock);
tid->paused--;
@@ -131,7 +154,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
struct list_head bf_head;
INIT_LIST_HEAD(&bf_head);
- ASSERT(tid->paused > 0);
+ BUG_ON(tid->paused <= 0);
spin_lock_bh(&txq->axq_lock);
tid->paused--;
@@ -143,7 +166,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
while (!list_empty(&tid->buf_q)) {
bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
- ASSERT(!bf_isretried(bf));
+ BUG_ON(bf_isretried(bf));
list_move_tail(&bf->list, &bf_head);
ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
}
@@ -178,7 +201,7 @@ static void ath_tx_addto_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
index = ATH_BA_INDEX(tid->seq_start, bf->bf_seqno);
cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
- ASSERT(tid->tx_buf[cindex] == NULL);
+ BUG_ON(tid->tx_buf[cindex] != NULL);
tid->tx_buf[cindex] = bf;
if (index >= ((tid->baw_tail - tid->baw_head) &
@@ -251,6 +274,7 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
ATH_TXBUF_RESET(tbf);
+ tbf->aphy = bf->aphy;
tbf->bf_mpdu = bf->bf_mpdu;
tbf->bf_buf_addr = bf->bf_buf_addr;
*(tbf->bf_desc) = *(bf->bf_desc);
@@ -267,7 +291,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
struct ath_node *an = NULL;
struct sk_buff *skb;
struct ieee80211_sta *sta;
+ struct ieee80211_hw *hw;
struct ieee80211_hdr *hdr;
+ struct ieee80211_tx_info *tx_info;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf_next, *bf_last = bf->bf_lastbf;
struct ath_desc *ds = bf_last->bf_desc;
@@ -280,9 +306,13 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data;
+ tx_info = IEEE80211_SKB_CB(skb);
+ hw = bf->aphy->hw;
+
rcu_read_lock();
- sta = ieee80211_find_sta(sc->hw, hdr->addr1);
+ /* XXX: use ieee80211_find_sta! */
+ sta = ieee80211_find_sta_by_hw(hw, hdr->addr1);
if (!sta) {
rcu_read_unlock();
return;
@@ -358,7 +388,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
else
INIT_LIST_HEAD(&bf_head);
} else {
- ASSERT(!list_empty(bf_q));
+ BUG_ON(list_empty(bf_q));
list_move_tail(&bf->list, &bf_head);
}
@@ -452,11 +482,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
struct ath_atx_tid *tid)
{
- const struct ath_rate_table *rate_table = sc->cur_rate_table;
struct sk_buff *skb;
struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rates;
- struct ath_tx_info_priv *tx_info_priv;
u32 max_4ms_framelen, frmlen;
u16 aggr_limit, legacy = 0;
int i;
@@ -464,7 +492,6 @@ 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;
- tx_info_priv = (struct ath_tx_info_priv *)tx_info->rate_driver_data[0];
/*
* Find the lowest frame length among the rate series that will have a
@@ -475,12 +502,20 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
for (i = 0; i < 4; i++) {
if (rates[i].count) {
- if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) {
+ int modeidx;
+ if (!(rates[i].flags & IEEE80211_TX_RC_MCS)) {
legacy = 1;
break;
}
- frmlen = rate_table->info[rates[i].idx].max_4ms_framelen;
+ if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
+ modeidx = MCS_HT40_SGI;
+ else if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+ modeidx = MCS_HT40;
+ else
+ modeidx = MCS_DEFAULT;
+
+ frmlen = ath_max_4ms_framelen[modeidx][rates[i].idx];
max_4ms_framelen = min(max_4ms_framelen, frmlen);
}
}
@@ -518,12 +553,11 @@ static u32 ath_lookup_rate(struct ath_softc *sc, struct ath_buf *bf,
static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
struct ath_buf *bf, u16 frmlen)
{
- const struct ath_rate_table *rt = sc->cur_rate_table;
struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
u32 nsymbits, nsymbols;
u16 minlen;
- u8 rc, flags, rix;
+ u8 flags, rix;
int width, half_gi, ndelim, mindelim;
/* Select standard number of delimiters based on frame length alone */
@@ -553,7 +587,6 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
rix = tx_info->control.rates[0].idx;
flags = tx_info->control.rates[0].flags;
- rc = rt->info[rix].ratecode;
width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0;
half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0;
@@ -565,7 +598,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
if (nsymbols == 0)
nsymbols = 1;
- nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
+ nsymbits = bits_per_symbol[rix][width];
minlen = (nsymbols * nsymbits) / BITS_PER_BYTE;
if (frmlen < minlen) {
@@ -694,7 +727,6 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* anchor last desc of aggregate */
ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
- txq->axq_aggr_depth++;
ath_tx_txqaddbuf(sc, txq, &bf_q);
TX_STAT_INC(txq->axq_qnum, a_aggr);
@@ -815,6 +847,7 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath9k_tx_queue_info qi;
int qnum;
@@ -854,9 +887,9 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
return NULL;
}
if (qnum >= ARRAY_SIZE(sc->tx.txq)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "qnum %u out of range, max %u!\n",
- qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
+ ath_print(common, ATH_DBG_FATAL,
+ "qnum %u out of range, max %u!\n",
+ qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq));
ath9k_hw_releasetxqueue(ah, qnum);
return NULL;
}
@@ -869,8 +902,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
INIT_LIST_HEAD(&txq->axq_acq);
spin_lock_init(&txq->axq_lock);
txq->axq_depth = 0;
- txq->axq_aggr_depth = 0;
- txq->axq_linkbuf = NULL;
txq->axq_tx_inprogress = false;
sc->tx.txqsetup |= 1<<qnum;
}
@@ -884,9 +915,9 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
switch (qtype) {
case ATH9K_TX_QUEUE_DATA:
if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "HAL AC %u out of range, max %zu!\n",
- haltype, ARRAY_SIZE(sc->tx.hwq_map));
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "HAL AC %u out of range, max %zu!\n",
+ haltype, ARRAY_SIZE(sc->tx.hwq_map));
return -1;
}
qnum = sc->tx.hwq_map[haltype];
@@ -906,18 +937,19 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype)
struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
{
struct ath_txq *txq = NULL;
+ u16 skb_queue = skb_get_queue_mapping(skb);
int qnum;
- qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc);
+ qnum = ath_get_hal_qnum(skb_queue, sc);
txq = &sc->tx.txq[qnum];
spin_lock_bh(&txq->axq_lock);
if (txq->axq_depth >= (ATH_TXBUF - 20)) {
- DPRINTF(sc, ATH_DBG_XMIT,
- "TX queue: %d is full, depth: %d\n",
- qnum, txq->axq_depth);
- ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_XMIT,
+ "TX queue: %d is full, depth: %d\n",
+ qnum, txq->axq_depth);
+ ath_mac80211_stop_queue(sc, skb_queue);
txq->stopped = 1;
spin_unlock_bh(&txq->axq_lock);
return NULL;
@@ -945,7 +977,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
return 0;
}
- ASSERT(sc->tx.txq[qnum].axq_qnum == qnum);
+ BUG_ON(sc->tx.txq[qnum].axq_qnum != qnum);
ath9k_hw_get_txq_props(ah, qnum, &qi);
qi.tqi_aifs = qinfo->tqi_aifs;
@@ -955,8 +987,8 @@ int ath_txq_update(struct ath_softc *sc, int qnum,
qi.tqi_readyTime = qinfo->tqi_readyTime;
if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to update hardware queue %u!\n", qnum);
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "Unable to update hardware queue %u!\n", qnum);
error = -EIO;
} else {
ath9k_hw_resettxqueue(ah, qnum);
@@ -1004,7 +1036,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
if (list_empty(&txq->axq_q)) {
txq->axq_link = NULL;
- txq->axq_linkbuf = NULL;
spin_unlock_bh(&txq->axq_lock);
break;
}
@@ -1055,6 +1086,7 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_txq *txq;
int i, npend = 0;
@@ -1076,14 +1108,15 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
if (npend) {
int r;
- DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n");
+ ath_print(common, ATH_DBG_XMIT,
+ "Unable to stop TxDMA. Reset HAL!\n");
spin_lock_bh(&sc->sc_resetlock);
r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);
if (r)
- DPRINTF(sc, ATH_DBG_FATAL,
- "Unable to reset hardware; reset status %d\n",
- r);
+ ath_print(common, ATH_DBG_FATAL,
+ "Unable to reset hardware; reset status %d\n",
+ r);
spin_unlock_bh(&sc->sc_resetlock);
}
@@ -1147,8 +1180,8 @@ int ath_tx_setup(struct ath_softc *sc, int haltype)
struct ath_txq *txq;
if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "HAL AC %u out of range, max %zu!\n",
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "HAL AC %u out of range, max %zu!\n",
haltype, ARRAY_SIZE(sc->tx.hwq_map));
return 0;
}
@@ -1172,6 +1205,7 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
struct list_head *head)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf;
/*
@@ -1186,21 +1220,20 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
list_splice_tail_init(head, &txq->axq_q);
txq->axq_depth++;
- txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list);
- DPRINTF(sc, ATH_DBG_QUEUE,
- "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
+ ath_print(common, ATH_DBG_QUEUE,
+ "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
if (txq->axq_link == NULL) {
ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
- DPRINTF(sc, ATH_DBG_XMIT,
- "TXDP[%u] = %llx (%p)\n",
- txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
+ ath_print(common, ATH_DBG_XMIT,
+ "TXDP[%u] = %llx (%p)\n",
+ txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
} else {
*txq->axq_link = bf->bf_daddr;
- DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
- txq->axq_qnum, txq->axq_link,
- ito64(bf->bf_daddr), bf->bf_desc);
+ ath_print(common, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n",
+ txq->axq_qnum, txq->axq_link,
+ ito64(bf->bf_daddr), bf->bf_desc);
}
txq->axq_link = &(bf->bf_lastbf->bf_desc->ds_link);
ath9k_hw_txstart(ah, txq->axq_qnum);
@@ -1420,22 +1453,14 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
int width, int half_gi, bool shortPreamble)
{
- const struct ath_rate_table *rate_table = sc->cur_rate_table;
u32 nbits, nsymbits, duration, nsymbols;
- u8 rc;
int streams, pktlen;
pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen;
- rc = rate_table->info[rix].ratecode;
-
- /* for legacy rates, use old function to compute packet duration */
- if (!IS_HT_RATE(rc))
- return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen,
- rix, shortPreamble);
/* find number of symbols: PLCP + data */
nbits = (pktlen << 3) + OFDM_PLCP_BITS;
- nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width];
+ nsymbits = bits_per_symbol[rix][width];
nsymbols = (nbits + nsymbits - 1) / nsymbits;
if (!half_gi)
@@ -1444,7 +1469,7 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
duration = SYMBOL_TIME_HALFGI(nsymbols);
/* addup duration for legacy/ht training and signal fields */
- streams = HT_RC_2_STREAMS(rc);
+ streams = HT_RC_2_STREAMS(rix);
duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams);
return duration;
@@ -1452,11 +1477,12 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf,
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
{
- const struct ath_rate_table *rt = sc->cur_rate_table;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_11n_rate_series series[4];
struct sk_buff *skb;
struct ieee80211_tx_info *tx_info;
struct ieee80211_tx_rate *rates;
+ const struct ieee80211_rate *rate;
struct ieee80211_hdr *hdr;
int i, flags = 0;
u8 rix = 0, ctsrate = 0;
@@ -1475,11 +1501,10 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
* checking the BSS's global flag.
* But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
*/
+ rate = ieee80211_get_rts_cts_rate(sc->hw, tx_info);
+ ctsrate = rate->hw_value;
if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
- ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode |
- rt->info[tx_info->control.rts_cts_rate_idx].short_preamble;
- else
- ctsrate = rt->info[tx_info->control.rts_cts_rate_idx].ratecode;
+ ctsrate |= rate->hw_value_short;
/*
* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive.
@@ -1502,18 +1527,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
flags &= ~(ATH9K_TXDESC_RTSENA);
for (i = 0; i < 4; i++) {
+ bool is_40, is_sgi, is_sp;
+ int phy;
+
if (!rates[i].count || (rates[i].idx < 0))
continue;
rix = rates[i].idx;
series[i].Tries = rates[i].count;
- series[i].ChSel = sc->tx_chainmask;
-
- if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
- series[i].Rate = rt->info[rix].ratecode |
- rt->info[rix].short_preamble;
- else
- series[i].Rate = rt->info[rix].ratecode;
+ series[i].ChSel = common->tx_chainmask;
if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)
series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
@@ -1522,10 +1544,36 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
if (rates[i].flags & IEEE80211_TX_RC_SHORT_GI)
series[i].RateFlags |= ATH9K_RATESERIES_HALFGI;
- series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
- (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0,
- (rates[i].flags & IEEE80211_TX_RC_SHORT_GI),
- (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE));
+ is_sgi = !!(rates[i].flags & IEEE80211_TX_RC_SHORT_GI);
+ is_40 = !!(rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH);
+ is_sp = !!(rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);
+
+ if (rates[i].flags & IEEE80211_TX_RC_MCS) {
+ /* MCS rates */
+ series[i].Rate = rix | 0x80;
+ series[i].PktDuration = ath_pkt_duration(sc, rix, bf,
+ is_40, is_sgi, is_sp);
+ continue;
+ }
+
+ /* legcay rates */
+ if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
+ !(rate->flags & IEEE80211_RATE_ERP_G))
+ phy = WLAN_RC_PHY_CCK;
+ else
+ phy = WLAN_RC_PHY_OFDM;
+
+ rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
+ series[i].Rate = rate->hw_value;
+ if (rate->hw_value_short) {
+ if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
+ series[i].Rate |= rate->hw_value_short;
+ } else {
+ is_sp = false;
+ }
+
+ series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
+ phy, rate->bitrate * 100, bf->bf_frmlen, rix, is_sp);
}
/* set dur_update_en for l-sig computation except for PS-Poll frames */
@@ -1546,24 +1594,36 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
struct ath_softc *sc = aphy->sc;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
- struct ath_tx_info_priv *tx_info_priv;
int hdrlen;
__le16 fc;
+ int padpos, padsize;
- tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC);
- if (unlikely(!tx_info_priv))
- return -ENOMEM;
- tx_info->rate_driver_data[0] = tx_info_priv;
- tx_info_priv->aphy = aphy;
- tx_info_priv->frame_type = txctl->frame_type;
+ tx_info->pad[0] = 0;
+ switch (txctl->frame_type) {
+ case ATH9K_NOT_INTERNAL:
+ break;
+ case ATH9K_INT_PAUSE:
+ tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_PAUSE;
+ /* fall through */
+ case ATH9K_INT_UNPAUSE:
+ tx_info->pad[0] |= ATH_TX_INFO_FRAME_TYPE_INTERNAL;
+ break;
+ }
hdrlen = ieee80211_get_hdrlen_from_skb(skb);
fc = hdr->frame_control;
ATH_TXBUF_RESET(bf);
- bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
+ bf->aphy = aphy;
+ bf->bf_frmlen = skb->len + FCS_LEN;
+ /* Remove the padding size from bf_frmlen, if any */
+ padpos = ath9k_cmn_padpos(hdr->frame_control);
+ padsize = padpos & 3;
+ if (padsize && skb->len>padpos+padsize) {
+ bf->bf_frmlen -= padsize;
+ }
- if (conf_is_ht(&sc->hw->conf) && !is_pae(skb))
+ if (conf_is_ht(&hw->conf) && !is_pae(skb))
bf->bf_state.bf_type |= BUF_HT;
bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
@@ -1585,13 +1645,20 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
skb->len, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
bf->bf_mpdu = NULL;
- kfree(tx_info_priv);
- tx_info->rate_driver_data[0] = NULL;
- DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error() on TX\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_FATAL,
+ "dma_mapping_error() on TX\n");
return -ENOMEM;
}
bf->bf_buf_addr = bf->bf_dmacontext;
+
+ /* tag if this is a nullfunc frame to enable PS when AP acks it */
+ if (ieee80211_is_nullfunc(fc) && ieee80211_has_pm(fc)) {
+ bf->bf_isnullfunc = true;
+ sc->sc_flags &= ~SC_OP_NULLFUNC_COMPLETED;
+ } else
+ bf->bf_isnullfunc = false;
+
return 0;
}
@@ -1669,12 +1736,13 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath_buf *bf;
int r;
bf = ath_tx_get_buffer(sc);
if (!bf) {
- DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n");
+ ath_print(common, ATH_DBG_XMIT, "TX buffers are full\n");
return -1;
}
@@ -1682,7 +1750,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
if (unlikely(r)) {
struct ath_txq *txq = txctl->txq;
- DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n");
+ ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
/* upon ath_tx_processq() this TX queue will be resumed, we
* guarantee this will happen by knowing beforehand that
@@ -1690,8 +1758,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
* on the queue */
spin_lock_bh(&txq->axq_lock);
if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
- ieee80211_stop_queue(sc->hw,
- skb_get_queue_mapping(skb));
+ ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
txq->stopped = 1;
}
spin_unlock_bh(&txq->axq_lock);
@@ -1712,6 +1779,7 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
{
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int hdrlen, padsize;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ath_tx_control txctl;
@@ -1736,7 +1804,8 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
if (hdrlen & 3) {
padsize = hdrlen % 4;
if (skb_headroom(skb) < padsize) {
- DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n");
+ ath_print(common, ATH_DBG_XMIT,
+ "TX CABQ padding failed\n");
dev_kfree_skb_any(skb);
return;
}
@@ -1746,10 +1815,11 @@ void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
txctl.txq = sc->beacon.cabq;
- DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb);
+ ath_print(common, ATH_DBG_XMIT,
+ "transmitting CABQ packet, skb: %p\n", skb);
if (ath_tx_start(hw, skb, &txctl) != 0) {
- DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n");
+ ath_print(common, ATH_DBG_XMIT, "CABQ TX failed\n");
goto exit;
}
@@ -1763,26 +1833,17 @@ exit:
/*****************/
static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
- int tx_flags)
+ struct ath_wiphy *aphy, int tx_flags)
{
struct ieee80211_hw *hw = sc->hw;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int hdrlen, padsize;
- int frame_type = ATH9K_NOT_INTERNAL;
- DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
+ ath_print(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
- if (tx_info_priv) {
- hw = tx_info_priv->aphy->hw;
- frame_type = tx_info_priv->frame_type;
- }
-
- if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
- tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
- kfree(tx_info_priv);
- tx_info->rate_driver_data[0] = NULL;
- }
+ if (aphy)
+ hw = aphy->hw;
if (tx_flags & ATH_TX_BAR)
tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
@@ -1805,18 +1866,19 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
if (sc->sc_flags & SC_OP_WAIT_FOR_TX_ACK) {
sc->sc_flags &= ~SC_OP_WAIT_FOR_TX_ACK;
- DPRINTF(sc, ATH_DBG_PS, "Going back to sleep after having "
- "received TX status (0x%x)\n",
+ ath_print(common, ATH_DBG_PS,
+ "Going back to sleep after having "
+ "received TX status (0x%x)\n",
sc->sc_flags & (SC_OP_WAIT_FOR_BEACON |
SC_OP_WAIT_FOR_CAB |
SC_OP_WAIT_FOR_PSPOLL_DATA |
SC_OP_WAIT_FOR_TX_ACK));
}
- if (frame_type == ATH9K_NOT_INTERNAL)
- ieee80211_tx_status(hw, skb);
- else
+ if (unlikely(tx_info->pad[0] & ATH_TX_INFO_FRAME_TYPE_INTERNAL))
ath9k_tx_status(hw, skb);
+ else
+ ieee80211_tx_status(hw, skb);
}
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
@@ -1839,7 +1901,7 @@ 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);
- ath_tx_complete(sc, skb, tx_flags);
+ ath_tx_complete(sc, skb, bf->aphy, tx_flags);
ath_debug_stat_tx(sc, txq, bf);
/*
@@ -1887,8 +1949,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
- struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
- struct ieee80211_hw *hw = tx_info_priv->aphy->hw;
+ struct ieee80211_hw *hw = bf->aphy->hw;
u8 i, tx_rateindex;
if (txok)
@@ -1897,22 +1958,29 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds,
tx_rateindex = ds->ds_txstat.ts_rateindex;
WARN_ON(tx_rateindex >= hw->max_rates);
- tx_info_priv->update_rc = update_rc;
+ if (update_rc)
+ tx_info->pad[0] |= ATH_TX_INFO_UPDATE_RC;
if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT)
tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
(bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
if (ieee80211_is_data(hdr->frame_control)) {
- memcpy(&tx_info_priv->tx, &ds->ds_txstat,
- sizeof(tx_info_priv->tx));
- tx_info_priv->n_frames = bf->bf_nframes;
- tx_info_priv->n_bad_frames = nbad;
+ if (ds->ds_txstat.ts_flags &
+ (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN))
+ tx_info->pad[0] |= ATH_TX_INFO_UNDERRUN;
+ if ((ds->ds_txstat.ts_status & ATH9K_TXERR_XRETRY) ||
+ (ds->ds_txstat.ts_status & ATH9K_TXERR_FIFO))
+ tx_info->pad[0] |= ATH_TX_INFO_XRETRY;
+ tx_info->status.ampdu_len = bf->bf_nframes;
+ tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
}
}
- for (i = tx_rateindex + 1; i < hw->max_rates; i++)
+ for (i = tx_rateindex + 1; i < hw->max_rates; i++) {
tx_info->status.rates[i].count = 0;
+ tx_info->status.rates[i].idx = -1;
+ }
tx_info->status.rates[tx_rateindex].count = bf->bf_retries + 1;
}
@@ -1926,7 +1994,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
if (qnum != -1) {
- ieee80211_wake_queue(sc->hw, qnum);
+ ath_mac80211_start_queue(sc, qnum);
txq->stopped = 0;
}
}
@@ -1936,21 +2004,21 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
{
struct ath_hw *ah = sc->sc_ah;
+ struct ath_common *common = ath9k_hw_common(ah);
struct ath_buf *bf, *lastbf, *bf_held = NULL;
struct list_head bf_head;
struct ath_desc *ds;
int txok;
int status;
- DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
- txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
- txq->axq_link);
+ ath_print(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
+ txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
+ txq->axq_link);
for (;;) {
spin_lock_bh(&txq->axq_lock);
if (list_empty(&txq->axq_q)) {
txq->axq_link = NULL;
- txq->axq_linkbuf = NULL;
spin_unlock_bh(&txq->axq_lock);
break;
}
@@ -1984,10 +2052,19 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
spin_unlock_bh(&txq->axq_lock);
break;
}
- if (bf->bf_desc == txq->axq_lastdsWithCTS)
- txq->axq_lastdsWithCTS = NULL;
- if (ds == txq->axq_gatingds)
- txq->axq_gatingds = NULL;
+
+ /*
+ * We now know the nullfunc frame has been ACKed so we
+ * can disable RX.
+ */
+ if (bf->bf_isnullfunc &&
+ (ds->ds_txstat.ts_status & ATH9K_TX_ACKED)) {
+ if ((sc->sc_flags & SC_OP_PS_ENABLED)) {
+ sc->ps_enabled = true;
+ ath9k_hw_setrxabort(sc->sc_ah, 1);
+ } else
+ sc->sc_flags |= SC_OP_NULLFUNC_COMPLETED;
+ }
/*
* Remove ath_buf's of the same transmit unit from txq,
@@ -2001,9 +2078,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
&txq->axq_q, lastbf->list.prev);
txq->axq_depth--;
- if (bf_isaggr(bf))
- txq->axq_aggr_depth--;
-
txok = (ds->ds_txstat.ts_status == 0);
txq->axq_tx_inprogress = false;
spin_unlock_bh(&txq->axq_lock);
@@ -2064,8 +2138,11 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
}
if (needreset) {
- DPRINTF(sc, ATH_DBG_RESET, "tx hung, resetting the chip\n");
+ ath_print(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
+ "tx hung, resetting the chip\n");
+ ath9k_ps_wakeup(sc);
ath_reset(sc, false);
+ ath9k_ps_restore(sc);
}
ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
@@ -2093,6 +2170,7 @@ void ath_tx_tasklet(struct ath_softc *sc)
int ath_tx_init(struct ath_softc *sc, int nbufs)
{
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
int error = 0;
spin_lock_init(&sc->tx.txbuflock);
@@ -2100,16 +2178,16 @@ int ath_tx_init(struct ath_softc *sc, int nbufs)
error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
"tx", nbufs, 1);
if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to allocate tx descriptors: %d\n", error);
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to allocate tx descriptors: %d\n", error);
goto err;
}
error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf,
"beacon", ATH_BCBUF, 1);
if (error != 0) {
- DPRINTF(sc, ATH_DBG_FATAL,
- "Failed to allocate beacon descriptors: %d\n", error);
+ ath_print(common, ATH_DBG_FATAL,
+ "Failed to allocate beacon descriptors: %d\n", error);
goto err;
}
OpenPOWER on IntegriCloud