ath9k: Add support for multiple secondary virtual wiphys
[linux-2.6.git] / drivers / net / wireless / ath9k / xmit.c
index d483f3c..3c48fa5 100644 (file)
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include "core.h"
+#include "ath9k.h"
 
 #define BITS_PER_BYTE           8
 #define OFDM_PLCP_BITS          22
@@ -308,7 +308,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                         * when perform internal reset in this routine.
                         * Only enable reset in STA mode for now.
                         */
-                       if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION)
+                       if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION)
                                needreset = 1;
                }
        }
@@ -772,24 +772,6 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
 /* Queue Management */
 /********************/
 
-static u32 ath_txq_depth(struct ath_softc *sc, int qnum)
-{
-       return sc->tx.txq[qnum].axq_depth;
-}
-
-static void ath_get_beaconconfig(struct ath_softc *sc, int if_id,
-                                struct ath_beacon_config *conf)
-{
-       struct ieee80211_hw *hw = sc->hw;
-
-       /* fill in beacon config data */
-
-       conf->beacon_interval = hw->conf.beacon_int;
-       conf->listen_interval = 100;
-       conf->dtim_count = 1;
-       conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
-}
-
 static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
                                          struct ath_txq *txq)
 {
@@ -809,7 +791,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_hal *ah = sc->sc_ah;
+       struct ath_hw *ah = sc->sc_ah;
        struct ath9k_tx_queue_info qi;
        int qnum;
 
@@ -926,7 +908,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
 int ath_txq_update(struct ath_softc *sc, int qnum,
                   struct ath9k_tx_queue_info *qinfo)
 {
-       struct ath_hal *ah = sc->sc_ah;
+       struct ath_hw *ah = sc->sc_ah;
        int error = 0;
        struct ath9k_tx_queue_info qi;
 
@@ -964,20 +946,18 @@ int ath_cabq_update(struct ath_softc *sc)
 {
        struct ath9k_tx_queue_info qi;
        int qnum = sc->beacon.cabq->axq_qnum;
-       struct ath_beacon_config conf;
 
        ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
        /*
         * Ensure the readytime % is within the bounds.
         */
-       if (sc->sc_config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
-               sc->sc_config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
-       else if (sc->sc_config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
-               sc->sc_config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
-
-       ath_get_beaconconfig(sc, ATH_IF_ID_ANY, &conf);
-       qi.tqi_readyTime =
-               (conf.beacon_interval * sc->sc_config.cabqReadytime) / 100;
+       if (sc->config.cabqReadytime < ATH9K_READY_TIME_LO_BOUND)
+               sc->config.cabqReadytime = ATH9K_READY_TIME_LO_BOUND;
+       else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
+               sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
+
+       qi.tqi_readyTime = (sc->hw->conf.beacon_int *
+                           sc->config.cabqReadytime) / 100;
        ath_txq_update(sc, qnum, &qi);
 
        return 0;
@@ -1047,7 +1027,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_hal *ah = sc->sc_ah;
+       struct ath_hw *ah = sc->sc_ah;
        struct ath_txq *txq;
        int i, npend = 0;
 
@@ -1072,7 +1052,7 @@ void ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
                DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n");
 
                spin_lock_bh(&sc->sc_resetlock);
-               r = ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, true);
+               r = ath9k_hw_reset(ah, sc->sc_ah->curchan, true);
                if (r)
                        DPRINTF(sc, ATH_DBG_FATAL,
                                "Unable to reset hardware; reset status %u\n",
@@ -1165,7 +1145,7 @@ int ath_tx_setup(struct ath_softc *sc, int haltype)
 static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
                             struct list_head *head)
 {
-       struct ath_hal *ah = sc->sc_ah;
+       struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf;
 
        /*
@@ -1386,8 +1366,6 @@ static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb,
 
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
                flags |= ATH9K_TXDESC_NOACK;
-       if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
-               flags |= ATH9K_TXDESC_RTSENA;
 
        return flags;
 }
@@ -1433,143 +1411,98 @@ 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)
 {
-       struct ath_hal *ah = sc->sc_ah;
-       struct ath_rate_table *rt;
-       struct ath_desc *ds = bf->bf_desc;
-       struct ath_desc *lastds = bf->bf_lastbf->bf_desc;
+       struct ath_rate_table *rt = sc->cur_rate_table;
        struct ath9k_11n_rate_series series[4];
        struct sk_buff *skb;
        struct ieee80211_tx_info *tx_info;
        struct ieee80211_tx_rate *rates;
        struct ieee80211_hdr *hdr;
-       struct ieee80211_hw *hw = sc->hw;
-       int i, flags, rtsctsena = 0, enable_g_protection = 0;
-       u32 ctsduration = 0;
-       u8 rix = 0, cix, ctsrate = 0;
-       __le16 fc;
+       int i, flags = 0;
+       u8 rix = 0, ctsrate = 0;
+       bool is_pspoll;
 
        memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
 
        skb = (struct sk_buff *)bf->bf_mpdu;
-       hdr = (struct ieee80211_hdr *)skb->data;
-       fc = hdr->frame_control;
        tx_info = IEEE80211_SKB_CB(skb);
        rates = tx_info->control.rates;
-
-       if (ieee80211_has_morefrags(fc) ||
-           (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) {
-               rates[1].count = rates[2].count = rates[3].count = 0;
-               rates[1].idx = rates[2].idx = rates[3].idx = 0;
-               rates[0].count = ATH_TXMAXTRY;
-       }
-
-       /* get the cix for the lowest valid rix */
-       rt = sc->cur_rate_table;
-       for (i = 3; i >= 0; i--) {
-               if (rates[i].count && (rates[i].idx >= 0)) {
-                       rix = rates[i].idx;
-                       break;
-               }
-       }
-
-       flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA));
-       cix = rt->info[rix].ctrl_rate;
-
-       /* All protection frames are transmited at 2Mb/s for 802.11g,
-        * otherwise we transmit them at 1Mb/s */
-       if (hw->conf.channel->band == IEEE80211_BAND_2GHZ &&
-         !conf_is_ht(&hw->conf))
-               enable_g_protection = 1;
+       hdr = (struct ieee80211_hdr *)skb->data;
+       is_pspoll = ieee80211_is_pspoll(hdr->frame_control);
 
        /*
-        * If 802.11g protection is enabled, determine whether to use RTS/CTS or
-        * just CTS.  Note that this is only done for OFDM/HT unicast frames.
+        * 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 (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK)
-           && (rt->info[rix].phy == WLAN_RC_PHY_OFDM ||
-               WLAN_RC_PHY_HT(rt->info[rix].phy))) {
-               if (sc->sc_protmode == PROT_M_RTSCTS)
-                       flags = ATH9K_TXDESC_RTSENA;
-               else if (sc->sc_protmode == PROT_M_CTSONLY)
-                       flags = ATH9K_TXDESC_CTSENA;
-
-               cix = rt->info[enable_g_protection].ctrl_rate;
-               rtsctsena = 1;
-       }
+       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;
 
-       /* For 11n, the default behavior is to enable RTS for hw retried frames.
-        * We enable the global flag here and let rate series flags determine
-        * which rates will actually use RTS.
+       /*
+        * ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive.
+        * Check the first rate in the series to decide whether RTS/CTS
+        * or CTS-to-self has to be used.
         */
-       if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) {
-               /* 802.11g protection not needed, use our default behavior */
-               if (!rtsctsena)
-                       flags = ATH9K_TXDESC_RTSENA;
-       }
+       if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)
+               flags = ATH9K_TXDESC_CTSENA;
+       else if (rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+               flags = ATH9K_TXDESC_RTSENA;
 
-       /* Set protection if aggregate protection on */
-       if (sc->sc_config.ath_aggr_prot &&
+       /* FIXME: Handle aggregation protection */
+       if (sc->config.ath_aggr_prot &&
            (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) {
                flags = ATH9K_TXDESC_RTSENA;
-               cix = rt->info[enable_g_protection].ctrl_rate;
-               rtsctsena = 1;
        }
 
        /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
-       if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit))
+       if (bf_isaggr(bf) && (bf->bf_al > sc->sc_ah->caps.rts_aggr_limit))
                flags &= ~(ATH9K_TXDESC_RTSENA);
 
-       /*
-        * CTS transmit rate is derived from the transmit rate by looking in the
-        * h/w rate table.  We must also factor in whether or not a short
-        * preamble is to be used. NB: cix is set above where RTS/CTS is enabled
-        */
-       ctsrate = rt->info[cix].ratecode |
-               (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0);
-
        for (i = 0; i < 4; i++) {
                if (!rates[i].count || (rates[i].idx < 0))
                        continue;
 
                rix = rates[i].idx;
-
-               series[i].Rate = rt->info[rix].ratecode |
-                       (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0);
-
                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].RateFlags = (
-                       (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ?
-                               ATH9K_RATESERIES_RTS_CTS : 0) |
-                       ((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ?
-                               ATH9K_RATESERIES_2040 : 0) |
-                       ((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ?
-                               ATH9K_RATESERIES_HALFGI : 0);
+               if (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)
+                       series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+               if (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
+                       series[i].RateFlags |= ATH9K_RATESERIES_2040;
+               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),
-                        bf_isshpreamble(bf));
-
-               series[i].ChSel = sc->sc_tx_chainmask;
-
-               if (rtsctsena)
-                       series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
+                        (rates[i].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE));
        }
 
        /* set dur_update_en for l-sig computation except for PS-Poll frames */
-       ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf),
-                                    ctsrate, ctsduration,
-                                    series, 4, flags);
+       ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
+                                    bf->bf_lastbf->bf_desc,
+                                    !is_pspoll, ctsrate,
+                                    0, series, 4, flags);
 
-       if (sc->sc_config.ath_aggr_prot && flags)
-               ath9k_hw_set11n_burstduration(ah, ds, 8192);
+       if (sc->config.ath_aggr_prot && flags)
+               ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
 }
 
-static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
+static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
                                struct sk_buff *skb,
                                struct ath_tx_control *txctl)
 {
+       struct ath_wiphy *aphy = hw->priv;
+       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;
@@ -1580,6 +1513,7 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
        if (unlikely(!tx_info_priv))
                return -ENOMEM;
        tx_info->rate_driver_data[0] = tx_info_priv;
+       tx_info_priv->aphy = aphy;
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
        fc = hdr->frame_control;
 
@@ -1587,14 +1521,6 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
 
        bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
 
-       if (ieee80211_is_data(fc))
-               bf->bf_state.bf_type |= BUF_DATA;
-       if (ieee80211_is_back_req(fc))
-               bf->bf_state.bf_type |= BUF_BAR;
-       if (ieee80211_is_pspoll(fc))
-               bf->bf_state.bf_type |= BUF_PSPOLL;
-       if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
-               bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE;
        if ((conf_is_ht(&sc->hw->conf) && !is_pae(skb) &&
             (tx_info->flags & IEEE80211_TX_CTL_AMPDU)))
                bf->bf_state.bf_type |= BUF_HT;
@@ -1637,7 +1563,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
        struct list_head bf_head;
        struct ath_desc *ds;
        struct ath_atx_tid *tid;
-       struct ath_hal *ah = sc->sc_ah;
+       struct ath_hw *ah = sc->sc_ah;
        int frm_type;
 
        frm_type = get_hw_packet_type(skb);
@@ -1691,9 +1617,11 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 }
 
 /* Upon failure caller should free skb */
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                 struct ath_tx_control *txctl)
 {
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_buf *bf;
        int r;
 
@@ -1703,7 +1631,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
                return -1;
        }
 
-       r = ath_tx_setup_buffer(sc, bf, skb, txctl);
+       r = ath_tx_setup_buffer(hw, bf, skb, txctl);
        if (unlikely(r)) {
                struct ath_txq *txq = txctl->txq;
 
@@ -1714,7 +1642,7 @@ int ath_tx_start(struct ath_softc *sc, 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 (ath_txq_depth(sc, txq->axq_qnum) > 1) {
+               if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
                        ieee80211_stop_queue(sc->hw,
                                skb_get_queue_mapping(skb));
                        txq->stopped = 1;
@@ -1733,8 +1661,10 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
        return 0;
 }
 
-void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
+void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        int hdrlen, padsize;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ath_tx_control txctl;
@@ -1771,7 +1701,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
 
        DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb);
 
-       if (ath_tx_start(sc, skb, &txctl) != 0) {
+       if (ath_tx_start(hw, skb, &txctl) != 0) {
                DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n");
                goto exit;
        }
@@ -1795,6 +1725,9 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
 
        DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
 
+       if (tx_info_priv)
+               hw = tx_info_priv->aphy->hw;
+
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
            tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
                kfree(tx_info_priv);
@@ -1898,6 +1831,7 @@ 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)
 {
        struct sk_buff *skb = (struct sk_buff *)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);
 
@@ -1907,7 +1841,7 @@ static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad)
 
        if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 &&
            (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) {
-               if (bf_isdata(bf)) {
+               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;
@@ -1923,7 +1857,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
 
        spin_lock_bh(&txq->axq_lock);
        if (txq->stopped &&
-           ath_txq_depth(sc, txq->axq_qnum) <= (ATH_TXBUF - 20)) {
+           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);
@@ -1935,7 +1869,7 @@ 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_hal *ah = sc->sc_ah;
+       struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf, *lastbf, *bf_held = NULL;
        struct list_head bf_head;
        struct ath_desc *ds;