ath9k: make per-WMM-AC queue sizes configurable via debugfs
[deliverable/linux.git] / drivers / net / wireless / ath / ath9k / xmit.c
index 23eaa1b26ebe5ca9a1a242ea4de5e9fa6508b02c..571d77362b617a4426198b90822a24fc0ccfdcaa 100644 (file)
@@ -64,7 +64,8 @@ static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
 static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
                                           struct ath_txq *txq,
                                           struct ath_atx_tid *tid,
-                                          struct sk_buff *skb);
+                                          struct sk_buff *skb,
+                                          bool dequeue);
 
 enum {
        MCS_HT20,
@@ -104,19 +105,19 @@ static int ath_max_4ms_framelen[4][32] = {
 /* Aggregation logic */
 /*********************/
 
-static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
        __acquires(&txq->axq_lock)
 {
        spin_lock_bh(&txq->axq_lock);
 }
 
-static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
        __releases(&txq->axq_lock)
 {
        spin_unlock_bh(&txq->axq_lock);
 }
 
-static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
+void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
        __releases(&txq->axq_lock)
 {
        struct sk_buff_head q;
@@ -811,7 +812,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
                fi = get_frame_info(skb);
                bf = fi->bf;
                if (!fi->bf)
-                       bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+                       bf = ath_tx_setup_buffer(sc, txq, tid, skb, true);
 
                if (!bf)
                        continue;
@@ -937,6 +938,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
        struct ieee80211_tx_rate *rates;
        const struct ieee80211_rate *rate;
        struct ieee80211_hdr *hdr;
+       struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
        int i;
        u8 rix = 0;
 
@@ -947,18 +949,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
 
        /* set dur_update_en for l-sig computation except for PS-Poll frames */
        info->dur_update = !ieee80211_is_pspoll(hdr->frame_control);
-
-       /*
-        * We check if Short Preamble is needed for the CTS rate by
-        * 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);
-       info->rtscts_rate = rate->hw_value;
-
-       if (tx_info->control.vif &&
-           tx_info->control.vif->bss_conf.use_short_preamble)
-               info->rtscts_rate |= rate->hw_value_short;
+       info->rtscts_rate = fi->rtscts_rate;
 
        for (i = 0; i < 4; i++) {
                bool is_40, is_sgi, is_sp;
@@ -1000,13 +991,13 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
                }
 
                /* legacy rates */
+               rate = &sc->sbands[tx_info->band].bitrates[rates[i].idx];
                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];
                info->rates[i].Rate = rate->hw_value;
                if (rate->hw_value_short) {
                        if (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
@@ -1174,6 +1165,7 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
 {
        struct ath_atx_tid *txtid;
        struct ath_node *an;
+       u8 density;
 
        an = (struct ath_node *)sta->drv_priv;
        txtid = ATH_AN_2_TID(an, tid);
@@ -1181,6 +1173,17 @@ int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
        if (txtid->state & (AGGR_CLEANUP | AGGR_ADDBA_COMPLETE))
                return -EAGAIN;
 
+       /* update ampdu factor/density, they may have changed. This may happen
+        * in HT IBSS when a beacon with HT-info is received after the station
+        * has already been added.
+        */
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
+               an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
+                                    sta->ht_cap.ampdu_factor);
+               density = ath9k_parse_mpdudensity(sta->ht_cap.ampdu_density);
+               an->mpdudensity = density;
+       }
+
        txtid->state |= AGGR_ADDBA_PROGRESS;
        txtid->paused = true;
        *ssn = txtid->seq_start = txtid->seq_next;
@@ -1535,7 +1538,7 @@ bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
        int i;
        u32 npend = 0;
 
-       if (sc->sc_flags & SC_OP_INVALID)
+       if (test_bit(SC_OP_INVALID, &sc->sc_flags))
                return true;
 
        ath9k_hw_abort_tx_dma(ah);
@@ -1726,7 +1729,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
                return;
        }
 
-       bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+       bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
        if (!bf)
                return;
 
@@ -1753,7 +1756,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
 
        bf = fi->bf;
        if (!bf)
-               bf = ath_tx_setup_buffer(sc, txq, tid, skb);
+               bf = ath_tx_setup_buffer(sc, txq, tid, skb, false);
 
        if (!bf)
                return;
@@ -1775,10 +1778,22 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
        struct ieee80211_sta *sta = tx_info->control.sta;
        struct ieee80211_key_conf *hw_key = tx_info->control.hw_key;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       const struct ieee80211_rate *rate;
        struct ath_frame_info *fi = get_frame_info(skb);
        struct ath_node *an = NULL;
        enum ath9k_key_type keytype;
+       bool short_preamble = false;
+
+       /*
+        * We check if Short Preamble is needed for the CTS rate by
+        * checking the BSS's global flag.
+        * But for the rate series, IEEE80211_TX_RC_USE_SHORT_PREAMBLE is used.
+        */
+       if (tx_info->control.vif &&
+           tx_info->control.vif->bss_conf.use_short_preamble)
+               short_preamble = true;
 
+       rate = ieee80211_get_rts_cts_rate(hw, tx_info);
        keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
 
        if (sta)
@@ -1793,6 +1808,9 @@ static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
                fi->keyix = ATH9K_TXKEYIX_INVALID;
        fi->keytype = keytype;
        fi->framelen = framelen;
+       fi->rtscts_rate = rate->hw_value;
+       if (short_preamble)
+               fi->rtscts_rate |= rate->hw_value_short;
 }
 
 u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
@@ -1814,7 +1832,8 @@ u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
 static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
                                           struct ath_txq *txq,
                                           struct ath_atx_tid *tid,
-                                          struct sk_buff *skb)
+                                          struct sk_buff *skb,
+                                          bool dequeue)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_frame_info *fi = get_frame_info(skb);
@@ -1863,6 +1882,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ath_softc *sc,
        return bf;
 
 error:
+       if (dequeue)
+               __skb_unlink(skb, &tid->buf_q);
        dev_kfree_skb_any(skb);
        return NULL;
 }
@@ -1893,7 +1914,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct sk_buff *skb,
                 */
                ath_tx_send_ampdu(sc, tid, skb, txctl);
        } else {
-               bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb);
+               bf = ath_tx_setup_buffer(sc, txctl->txq, tid, skb, false);
                if (!bf)
                        return;
 
@@ -1967,7 +1988,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        ath_txq_lock(sc, txq);
        if (txq == sc->tx.txq_map[q] &&
-           ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
+           ++txq->pending_frames > sc->tx.txq_max_pending[q] &&
+           !txq->stopped) {
                ieee80211_stop_queue(sc->hw, q);
                txq->stopped = true;
        }
@@ -1990,6 +2012,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
        int q, padpos, padsize;
+       unsigned long flags;
 
        ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
 
@@ -2008,6 +2031,7 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                skb_pull(skb, padsize);
        }
 
+       spin_lock_irqsave(&sc->sc_pm_lock, flags);
        if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
                sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
                ath_dbg(common, PS,
@@ -2017,13 +2041,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                                        PS_WAIT_FOR_PSPOLL_DATA |
                                        PS_WAIT_FOR_TX_ACK));
        }
+       spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 
        q = skb_get_queue_mapping(skb);
        if (txq == sc->tx.txq_map[q]) {
                if (WARN_ON(--txq->pending_frames < 0))
                        txq->pending_frames = 0;
 
-               if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
+               if (txq->stopped &&
+                   txq->pending_frames < sc->tx.txq_max_pending[q]) {
                        ieee80211_wake_queue(sc->hw, q);
                        txq->stopped = false;
                }
@@ -2227,46 +2253,6 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
        ath_txq_unlock_complete(sc, txq);
 }
 
-static void ath_tx_complete_poll_work(struct work_struct *work)
-{
-       struct ath_softc *sc = container_of(work, struct ath_softc,
-                       tx_complete_work.work);
-       struct ath_txq *txq;
-       int i;
-       bool needreset = false;
-#ifdef CONFIG_ATH9K_DEBUGFS
-       sc->tx_complete_poll_work_seen++;
-#endif
-
-       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
-               if (ATH_TXQ_SETUP(sc, i)) {
-                       txq = &sc->tx.txq[i];
-                       ath_txq_lock(sc, txq);
-                       if (txq->axq_depth) {
-                               if (txq->axq_tx_inprogress) {
-                                       needreset = true;
-                                       ath_txq_unlock(sc, txq);
-                                       break;
-                               } else {
-                                       txq->axq_tx_inprogress = true;
-                               }
-                       }
-                       ath_txq_unlock_complete(sc, txq);
-               }
-
-       if (needreset) {
-               ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
-                       "tx hung, resetting the chip\n");
-               RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
-               ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
-       }
-
-       ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
-                       msecs_to_jiffies(ATH_TX_COMPLETE_POLL_INT));
-}
-
-
-
 void ath_tx_tasklet(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
This page took 0.105134 seconds and 5 git commands to generate.