| Index: chromeos/compat-wireless/drivers/net/wireless/ath/ath9k/xmit.c
|
| diff --git a/chromeos/compat-wireless/drivers/net/wireless/ath/ath9k/xmit.c b/chromeos/compat-wireless/drivers/net/wireless/ath/ath9k/xmit.c
|
| index d99a4f656b7a18af41d3a535f4fb440aadec19e6..f54e8d46ee35ff3ea8564ca4668f09cf866ac2ee 100644
|
| --- a/chromeos/compat-wireless/drivers/net/wireless/ath/ath9k/xmit.c
|
| +++ b/chromeos/compat-wireless/drivers/net/wireless/ath/ath9k/xmit.c
|
| @@ -124,7 +124,7 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
|
|
|
| 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];
|
| + struct ath_txq *txq = tid->ac->txq;
|
|
|
| WARN_ON(!tid->paused);
|
|
|
| @@ -142,7 +142,7 @@ unlock:
|
|
|
| static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
|
| {
|
| - struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum];
|
| + struct ath_txq *txq = tid->ac->txq;
|
| struct ath_buf *bf;
|
| struct list_head bf_head;
|
| struct ath_tx_status ts;
|
| @@ -175,9 +175,9 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
|
| index = ATH_BA_INDEX(tid->seq_start, seqno);
|
| cindex = (tid->baw_head + index) & (ATH_TID_MAX_BUFS - 1);
|
|
|
| - __clear_bit(cindex, tid->tx_buf);
|
| + tid->tx_buf[cindex] = NULL;
|
|
|
| - while (tid->baw_head != tid->baw_tail && !test_bit(tid->baw_head, tid->tx_buf)) {
|
| + while (tid->baw_head != tid->baw_tail && !tid->tx_buf[tid->baw_head]) {
|
| INCR(tid->seq_start, IEEE80211_SEQ_MAX);
|
| INCR(tid->baw_head, ATH_TID_MAX_BUFS);
|
| }
|
| @@ -193,7 +193,9 @@ 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);
|
| - __set_bit(cindex, tid->tx_buf);
|
| +
|
| + BUG_ON(tid->tx_buf[cindex] != NULL);
|
| + tid->tx_buf[cindex] = bf;
|
|
|
| if (index >= ((tid->baw_tail - tid->baw_head) &
|
| (ATH_TID_MAX_BUFS - 1))) {
|
| @@ -317,6 +319,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
| int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
|
| bool rc_update = true;
|
| struct ieee80211_tx_rate rates[4];
|
| + int nframes;
|
|
|
| skb = bf->bf_mpdu;
|
| hdr = (struct ieee80211_hdr *)skb->data;
|
| @@ -325,6 +328,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
| hw = bf->aphy->hw;
|
|
|
| memcpy(rates, tx_info->control.rates, sizeof(rates));
|
| + nframes = bf->bf_nframes;
|
|
|
| rcu_read_lock();
|
|
|
| @@ -342,7 +346,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
| !bf->bf_stale || bf_next != NULL)
|
| list_move_tail(&bf->list, &bf_head);
|
|
|
| - ath_tx_rc_status(bf, ts, 0, 0, false);
|
| + ath_tx_rc_status(bf, ts, 1, 0, false);
|
| ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
|
| 0, 0);
|
|
|
| @@ -447,6 +451,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
|
|
|
| if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
|
| memcpy(tx_info->control.rates, rates, sizeof(rates));
|
| + bf->bf_nframes = nframes;
|
| ath_tx_rc_status(bf, ts, nbad, txok, true);
|
| rc_update = false;
|
| } else {
|
| @@ -810,7 +815,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
|
| {
|
| 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 = &sc->tx.txq[txtid->ac->qnum];
|
| + struct ath_txq *txq = txtid->ac->txq;
|
|
|
| if (txtid->state & AGGR_CLEANUP)
|
| return;
|
| @@ -855,6 +860,20 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
|
| }
|
| }
|
|
|
| +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
|
| +{
|
| + struct ath_atx_tid *txtid;
|
| +
|
| + if (!(sc->sc_flags & SC_OP_TXAGGR))
|
| + return false;
|
| +
|
| + txtid = ATH_AN_2_TID(an, tidno);
|
| +
|
| + if (!(txtid->state & (AGGR_ADDBA_COMPLETE | AGGR_ADDBA_PROGRESS)))
|
| + return true;
|
| + return false;
|
| +}
|
| +
|
| /********************/
|
| /* Queue Management */
|
| /********************/
|
| @@ -881,10 +900,16 @@ 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;
|
| + static const int subtype_txq_to_hwq[] = {
|
| + [WME_AC_BE] = ATH_TXQ_AC_BE,
|
| + [WME_AC_BK] = ATH_TXQ_AC_BK,
|
| + [WME_AC_VI] = ATH_TXQ_AC_VI,
|
| + [WME_AC_VO] = ATH_TXQ_AC_VO,
|
| + };
|
| int qnum, i;
|
|
|
| memset(&qi, 0, sizeof(qi));
|
| - qi.tqi_subtype = subtype;
|
| + qi.tqi_subtype = subtype_txq_to_hwq[subtype];
|
| qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT;
|
| qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT;
|
| qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT;
|
| @@ -933,7 +958,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
|
| if (!ATH_TXQ_SETUP(sc, qnum)) {
|
| struct ath_txq *txq = &sc->tx.txq[qnum];
|
|
|
| - txq->axq_class = subtype;
|
| txq->axq_qnum = qnum;
|
| txq->axq_link = NULL;
|
| INIT_LIST_HEAD(&txq->axq_q);
|
| @@ -1082,15 +1106,6 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
|
| txq->axq_tx_inprogress = false;
|
| spin_unlock_bh(&txq->axq_lock);
|
|
|
| - /* flush any pending frames if aggregation is enabled */
|
| - if (sc->sc_flags & SC_OP_TXAGGR) {
|
| - if (!retry_tx) {
|
| - spin_lock_bh(&txq->axq_lock);
|
| - ath_txq_drain_pending_buffers(sc, txq);
|
| - spin_unlock_bh(&txq->axq_lock);
|
| - }
|
| - }
|
| -
|
| if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
|
| spin_lock_bh(&txq->axq_lock);
|
| while (!list_empty(&txq->txq_fifo_pending)) {
|
| @@ -1111,6 +1126,15 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
|
| }
|
| spin_unlock_bh(&txq->axq_lock);
|
| }
|
| +
|
| + /* flush any pending frames if aggregation is enabled */
|
| + if (sc->sc_flags & SC_OP_TXAGGR) {
|
| + if (!retry_tx) {
|
| + spin_lock_bh(&txq->axq_lock);
|
| + ath_txq_drain_pending_buffers(sc, txq);
|
| + spin_unlock_bh(&txq->axq_lock);
|
| + }
|
| + }
|
| }
|
|
|
| void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
|
| @@ -1203,24 +1227,6 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
|
| }
|
| }
|
|
|
| -int ath_tx_setup(struct ath_softc *sc, int haltype)
|
| -{
|
| - struct ath_txq *txq;
|
| -
|
| - if (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 0;
|
| - }
|
| - txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype);
|
| - if (txq != NULL) {
|
| - sc->tx.hwq_map[haltype] = txq->axq_qnum;
|
| - return 1;
|
| - } else
|
| - return 0;
|
| -}
|
| -
|
| /***********/
|
| /* TX, DMA */
|
| /***********/
|
| @@ -1725,6 +1731,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
|
| goto tx_done;
|
| }
|
|
|
| + WARN_ON(tid->ac->txq != txctl->txq);
|
| if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
|
| /*
|
| * Try aggregation if it's a unicast data frame
|
| @@ -1764,6 +1771,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
| return -1;
|
| }
|
|
|
| + q = skb_get_queue_mapping(skb);
|
| r = ath_tx_setup_buffer(hw, bf, skb, txctl);
|
| if (unlikely(r)) {
|
| ath_print(common, ATH_DBG_FATAL, "TX mem alloc failure\n");
|
| @@ -1773,8 +1781,9 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
| * we will at least have to run TX completionon one buffer
|
| * on the queue */
|
| spin_lock_bh(&txq->axq_lock);
|
| - if (!txq->stopped && txq->axq_depth > 1) {
|
| - ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
|
| + if (txq == sc->tx.txq_map[q] && !txq->stopped &&
|
| + txq->axq_depth > 1) {
|
| + ath_mac80211_stop_queue(sc, q);
|
| txq->stopped = 1;
|
| }
|
| spin_unlock_bh(&txq->axq_lock);
|
| @@ -1784,13 +1793,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
|
| return r;
|
| }
|
|
|
| - q = skb_get_queue_mapping(skb);
|
| - if (q >= 4)
|
| - q = 0;
|
| -
|
| spin_lock_bh(&txq->axq_lock);
|
| - if (++sc->tx.pending_frames[q] > ATH_MAX_QDEPTH && !txq->stopped) {
|
| - ath_mac80211_stop_queue(sc, skb_get_queue_mapping(skb));
|
| + if (txq == sc->tx.txq_map[q] &&
|
| + ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
|
| + ath_mac80211_stop_queue(sc, q);
|
| txq->stopped = 1;
|
| }
|
| spin_unlock_bh(&txq->axq_lock);
|
| @@ -1858,7 +1864,8 @@ exit:
|
| /*****************/
|
|
|
| static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
| - struct ath_wiphy *aphy, int tx_flags)
|
| + struct ath_wiphy *aphy, int tx_flags,
|
| + struct ath_txq *txq)
|
| {
|
| struct ieee80211_hw *hw = sc->hw;
|
| struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
|
| @@ -1905,11 +1912,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
|
| ath9k_tx_status(hw, skb);
|
| else {
|
| q = skb_get_queue_mapping(skb);
|
| - if (q >= 4)
|
| - q = 0;
|
| -
|
| - if (--sc->tx.pending_frames[q] < 0)
|
| - sc->tx.pending_frames[q] = 0;
|
| + if (txq == sc->tx.txq_map[q]) {
|
| + spin_lock_bh(&txq->axq_lock);
|
| + if (WARN_ON(--txq->pending_frames < 0))
|
| + txq->pending_frames = 0;
|
| + spin_unlock_bh(&txq->axq_lock);
|
| + }
|
|
|
| ieee80211_tx_status(hw, skb);
|
| }
|
| @@ -1943,8 +1951,9 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
|
| else
|
| complete(&sc->paprd_complete);
|
| } else {
|
| - ath_tx_complete(sc, skb, bf->aphy, tx_flags);
|
| - ath_debug_stat_tx(sc, txq, bf, ts);
|
| + ath_debug_stat_tx(sc, bf, ts);
|
| + ath_tx_complete(sc, skb, bf->aphy, tx_flags, txq);
|
| +
|
| }
|
|
|
| /*
|
| @@ -2001,9 +2010,15 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
|
|
| if (ts->ts_status & ATH9K_TXERR_FILT)
|
| tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
|
| - if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc)
|
| + if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && update_rc) {
|
| tx_info->flags |= IEEE80211_TX_STAT_AMPDU;
|
|
|
| + BUG_ON(nbad > bf->bf_nframes);
|
| +
|
| + tx_info->status.ampdu_len = bf->bf_nframes;
|
| + tx_info->status.ampdu_ack_len = bf->bf_nframes - nbad;
|
| + }
|
| +
|
| if ((ts->ts_status & ATH9K_TXERR_FILT) == 0 &&
|
| (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0 && update_rc) {
|
| if (ieee80211_is_data(hdr->frame_control)) {
|
| @@ -2013,8 +2028,6 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
| if ((ts->ts_status & ATH9K_TXERR_XRETRY) ||
|
| (ts->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;
|
| }
|
| }
|
|
|
| @@ -2026,16 +2039,13 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_tx_status *ts,
|
| tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
|
| }
|
|
|
| -static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
|
| +static void ath_wake_mac80211_queue(struct ath_softc *sc, int qnum)
|
| {
|
| - int qnum;
|
| -
|
| - qnum = ath_get_mac80211_qnum(txq->axq_class, sc);
|
| - if (qnum == -1)
|
| - return;
|
| + struct ath_txq *txq;
|
|
|
| + txq = sc->tx.txq_map[qnum];
|
| spin_lock_bh(&txq->axq_lock);
|
| - if (txq->stopped && sc->tx.pending_frames[qnum] < ATH_MAX_QDEPTH) {
|
| + if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
|
| if (ath_mac80211_start_queue(sc, qnum))
|
| txq->stopped = 0;
|
| }
|
| @@ -2052,6 +2062,7 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
| struct ath_tx_status ts;
|
| int txok;
|
| int status;
|
| + int qnum;
|
|
|
| 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),
|
| @@ -2136,15 +2147,18 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
|
| */
|
| if (ts.ts_status & ATH9K_TXERR_XRETRY)
|
| bf->bf_state.bf_type |= BUF_XRETRY;
|
| - ath_tx_rc_status(bf, &ts, 0, txok, true);
|
| + ath_tx_rc_status(bf, &ts, txok ? 0 : 1, txok, true);
|
| }
|
|
|
| + qnum = skb_get_queue_mapping(bf->bf_mpdu);
|
| +
|
| if (bf_isampdu(bf))
|
| ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok);
|
| else
|
| ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
|
|
|
| - ath_wake_mac80211_queue(sc, txq);
|
| + if (txq == sc->tx.txq_map[qnum])
|
| + ath_wake_mac80211_queue(sc, qnum);
|
|
|
| spin_lock_bh(&txq->axq_lock);
|
| if (sc->sc_flags & SC_OP_TXAGGR)
|
| @@ -2181,7 +2195,7 @@ static void ath_tx_complete_poll_work(struct work_struct *work)
|
| 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);
|
| + ath_reset(sc, true);
|
| ath9k_ps_restore(sc);
|
| }
|
|
|
| @@ -2214,6 +2228,7 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
| struct list_head bf_head;
|
| int status;
|
| int txok;
|
| + int qnum;
|
|
|
| for (;;) {
|
| status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
|
| @@ -2265,16 +2280,19 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
|
| if (!bf_isampdu(bf)) {
|
| if (txs.ts_status & ATH9K_TXERR_XRETRY)
|
| bf->bf_state.bf_type |= BUF_XRETRY;
|
| - ath_tx_rc_status(bf, &txs, 0, txok, true);
|
| + ath_tx_rc_status(bf, &txs, txok ? 0 : 1, txok, true);
|
| }
|
|
|
| + qnum = skb_get_queue_mapping(bf->bf_mpdu);
|
| +
|
| if (bf_isampdu(bf))
|
| ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs, txok);
|
| else
|
| ath_tx_complete_buf(sc, bf, txq, &bf_head,
|
| &txs, txok, 0);
|
|
|
| - ath_wake_mac80211_queue(sc, txq);
|
| + if (txq == sc->tx.txq_map[qnum])
|
| + ath_wake_mac80211_queue(sc, qnum);
|
|
|
| spin_lock_bh(&txq->axq_lock);
|
| if (!list_empty(&txq->txq_fifo_pending)) {
|
| @@ -2406,7 +2424,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
|
| for (acno = 0, ac = &an->ac[acno];
|
| acno < WME_NUM_AC; acno++, ac++) {
|
| ac->sched = false;
|
| - ac->qnum = sc->tx.hwq_map[acno];
|
| + ac->txq = sc->tx.txq_map[acno];
|
| INIT_LIST_HEAD(&ac->tid_q);
|
| }
|
| }
|
| @@ -2416,17 +2434,13 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an)
|
| struct ath_atx_ac *ac;
|
| struct ath_atx_tid *tid;
|
| struct ath_txq *txq;
|
| - int i, tidno;
|
| + int tidno;
|
|
|
| for (tidno = 0, tid = &an->tid[tidno];
|
| tidno < WME_NUM_TID; tidno++, tid++) {
|
| - i = tid->ac->qnum;
|
| -
|
| - if (!ATH_TXQ_SETUP(sc, i))
|
| - continue;
|
|
|
| - txq = &sc->tx.txq[i];
|
| ac = tid->ac;
|
| + txq = ac->txq;
|
|
|
| spin_lock_bh(&txq->axq_lock);
|
|
|
|
|