diff options
Diffstat (limited to 'drivers/net/wireless/ath/ath9k/xmit.c')
-rw-r--r-- | drivers/net/wireless/ath/ath9k/xmit.c | 354 |
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 42551a48c8a..564c6cb1c2b 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; } |