Merge branch 'x86-platform-for-linus' of git://git.kernel.org/pub/scm/linux/kernel...
[pandora-kernel.git] / drivers / net / wireless / ath / ath9k / xmit.c
index aa44777..30ef2df 100644 (file)
@@ -294,7 +294,6 @@ static struct ath_buf* ath_clone_txbuf(struct ath_softc *sc, struct ath_buf *bf)
        tbf->bf_buf_addr = bf->bf_buf_addr;
        memcpy(tbf->bf_desc, bf->bf_desc, sc->sc_ah->caps.tx_desc_len);
        tbf->bf_state = bf->bf_state;
-       tbf->bf_dmacontext = bf->bf_dmacontext;
 
        return tbf;
 }
@@ -317,6 +316,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 +325,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();
 
@@ -341,7 +342,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);
 
@@ -446,6 +447,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 {
@@ -671,6 +673,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
        u16 aggr_limit = 0, al = 0, bpad = 0,
                al_delta, h_baw = tid->baw_size / 2;
        enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
+       struct ieee80211_tx_info *tx_info;
 
        bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
 
@@ -697,6 +700,11 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
                        break;
                }
 
+               tx_info = IEEE80211_SKB_CB(bf->bf_mpdu);
+               if (nframes && ((tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) ||
+                       !(tx_info->control.rates[0].flags & IEEE80211_TX_RC_MCS)))
+                       break;
+
                /* do not exceed subframe limit */
                if (nframes >= min((int)h_baw, ATH_AMPDU_SUBFRAME_DEFAULT)) {
                        status = ATH_AGGR_LIMITED;
@@ -1637,17 +1645,16 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
 
        bf->bf_mpdu = skb;
 
-       bf->bf_dmacontext = dma_map_single(sc->dev, skb->data,
-                                          skb->len, DMA_TO_DEVICE);
-       if (unlikely(dma_mapping_error(sc->dev, bf->bf_dmacontext))) {
+       bf->bf_buf_addr = dma_map_single(sc->dev, skb->data,
+                                        skb->len, DMA_TO_DEVICE);
+       if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
                bf->bf_mpdu = NULL;
+               bf->bf_buf_addr = 0;
                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;
-
        bf->bf_tx_aborted = false;
 
        return 0;
@@ -1911,7 +1918,8 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
                        tx_flags |= ATH_TX_XRETRY;
        }
 
-       dma_unmap_single(sc->dev, bf->bf_dmacontext, skb->len, DMA_TO_DEVICE);
+       dma_unmap_single(sc->dev, bf->bf_buf_addr, skb->len, DMA_TO_DEVICE);
+       bf->bf_buf_addr = 0;
 
        if (bf->bf_state.bfs_paprd) {
                if (time_after(jiffies,
@@ -1921,9 +1929,13 @@ 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_tx_complete(sc, skb, bf->aphy, tx_flags);
        }
+       /* At this point, skb (bf->bf_mpdu) is consumed...make sure we don't
+        * accidentally reference it later.
+        */
+       bf->bf_mpdu = NULL;
 
        /*
         * Return the list of ath_buf of this mpdu to free queue
@@ -1979,9 +1991,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)) {
@@ -1991,8 +2009,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;
                }
        }
 
@@ -2102,7 +2118,7 @@ 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);
                }
 
                if (bf_isampdu(bf))
@@ -2147,7 +2163,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);
        }
 
@@ -2220,7 +2236,7 @@ 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);
                }
 
                if (bf_isampdu(bf))