iPXE
Defines | Enumerations | Functions
ath9k_xmit.c File Reference
#include <ipxe/io.h>
#include "ath9k.h"
#include "ar9003_mac.h"

Go to the source code of this file.

Defines

#define BITS_PER_BYTE   8
#define OFDM_PLCP_BITS   22
#define HT_RC_2_STREAMS(_rc)   ((((_rc) & 0x78) >> 3) + 1)
#define L_STF   8
#define L_LTF   8
#define L_SIG   4
#define HT_SIG   8
#define HT_STF   4
#define HT_LTF(_ns)   (4 * (_ns))
#define SYMBOL_TIME(_ns)   ((_ns) << 2) /* ns * 4 us */
#define SYMBOL_TIME_HALFGI(_ns)   (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */
#define NUM_SYMBOLS_PER_USEC(_usec)   (_usec >> 2)
#define NUM_SYMBOLS_PER_USEC_HALFGI(_usec)   (((_usec*5)-4)/18)
#define IS_HT_RATE(_rate)   ((_rate) & 0x80)

Enumerations

enum  { MCS_HT20, MCS_HT20_SGI, MCS_HT40, MCS_HT40_SGI }

Functions

static void ath_tx_send_normal (struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head)
static void ath_tx_complete_buf (struct ath_softc *sc, struct ath_buf *bf, struct ath_txq *txq, struct list_head *bf_q, struct ath_tx_status *ts, int txok, int sendbar)
static void ath_tx_txqaddbuf (struct ath_softc *sc, struct ath_txq *txq, struct list_head *head)
static void ath_buf_set_rate (struct ath_softc *sc, struct ath_buf *bf, int len)
static void ath_tx_queue_tid (struct ath_txq *txq, struct ath_atx_tid *tid)
static struct ath_bufath_tx_get_buffer (struct ath_softc *sc)
static void ath_tx_return_buffer (struct ath_softc *sc, struct ath_buf *bf)
struct ath_txqath_txq_setup (struct ath_softc *sc, int qtype, int subtype)
void ath_draintxq (struct ath_softc *sc, struct ath_txq *txq, int retry_tx __unused)
int ath_drain_all_txq (struct ath_softc *sc, int retry_tx)
void ath_tx_cleanupq (struct ath_softc *sc, struct ath_txq *txq)
void ath_txq_schedule (struct ath_softc *sc __unused, struct ath_txq *txq)
static enum ath9k_pkt_type get_hw_packet_type (struct io_buffer *iob)
static int setup_tx_flags (struct io_buffer *iob __unused)
u8 ath_txchainmask_reduction (struct ath_softc *sc, u8 chainmask, u32 rate)
static struct ath_bufath_tx_setup_buffer (struct net80211_device *dev, struct ath_txq *txq, struct io_buffer *iob)
static void ath_tx_start_dma (struct ath_softc *sc, struct ath_buf *bf, struct ath_tx_control *txctl)
int ath_tx_start (struct net80211_device *dev, struct io_buffer *iob, struct ath_tx_control *txctl)
static void ath_tx_complete (struct ath_softc *sc, struct io_buffer *iob, int tx_flags __unused, struct ath_tx_status *ts, struct ath_txq *txq)
static void ath_tx_processq (struct ath_softc *sc, struct ath_txq *txq)
static void ath_tx_complete_poll_work (struct ath_softc *sc)
void ath_tx_tasklet (struct ath_softc *sc)
int ath_tx_init (struct ath_softc *sc, int nbufs)
void ath_tx_cleanup (struct ath_softc *sc)

Define Documentation

#define BITS_PER_BYTE   8

Definition at line 25 of file ath9k_xmit.c.

#define OFDM_PLCP_BITS   22

Definition at line 26 of file ath9k_xmit.c.

Referenced by ath9k_hw_computetxtime().

#define HT_RC_2_STREAMS (   _rc)    ((((_rc) & 0x78) >> 3) + 1)

Definition at line 27 of file ath9k_xmit.c.

#define L_STF   8

Definition at line 28 of file ath9k_xmit.c.

#define L_LTF   8

Definition at line 29 of file ath9k_xmit.c.

#define L_SIG   4

Definition at line 30 of file ath9k_xmit.c.

#define HT_SIG   8

Definition at line 31 of file ath9k_xmit.c.

#define HT_STF   4

Definition at line 32 of file ath9k_xmit.c.

#define HT_LTF (   _ns)    (4 * (_ns))

Definition at line 33 of file ath9k_xmit.c.

#define SYMBOL_TIME (   _ns)    ((_ns) << 2) /* ns * 4 us */

Definition at line 34 of file ath9k_xmit.c.

#define SYMBOL_TIME_HALFGI (   _ns)    (((_ns) * 18 + 4) / 5) /* ns * 3.6 us */

Definition at line 35 of file ath9k_xmit.c.

#define NUM_SYMBOLS_PER_USEC (   _usec)    (_usec >> 2)

Definition at line 36 of file ath9k_xmit.c.

#define NUM_SYMBOLS_PER_USEC_HALFGI (   _usec)    (((_usec*5)-4)/18)

Definition at line 37 of file ath9k_xmit.c.

#define IS_HT_RATE (   _rate)    ((_rate) & 0x80)

Definition at line 40 of file ath9k_xmit.c.


Enumeration Type Documentation

anonymous enum
Enumerator:
MCS_HT20 
MCS_HT20_SGI 
MCS_HT40 
MCS_HT40_SGI 

Definition at line 52 of file ath9k_xmit.c.


Function Documentation

static void ath_tx_send_normal ( struct ath_softc sc,
struct ath_txq txq,
struct ath_atx_tid tid,
struct list_head bf_head 
) [static]

Definition at line 363 of file ath9k_xmit.c.

References ath_buf_set_rate(), ath_tx_txqaddbuf(), ath_buf::bf_lastbf, ath_buf::bf_mpdu, ath_buf::bf_state, ath_buf_state::bf_type, BUF_AMPDU, FCS_LEN, IEEE80211_SEQ_MAX, INCR, iob_len(), ath_buf::list, list_first_entry, and ath_atx_tid::seq_start.

Referenced by ath_tx_start_dma().

{
        struct ath_buf *bf;

        bf = list_first_entry(bf_head, struct ath_buf, list);
        bf->bf_state.bf_type &= ~BUF_AMPDU;

        /* update starting sequence number for subsequent ADDBA request */
        if (tid)
                INCR(tid->seq_start, IEEE80211_SEQ_MAX);

        bf->bf_lastbf = bf;
        ath_buf_set_rate(sc, bf, iob_len(bf->bf_mpdu) + FCS_LEN);
        ath_tx_txqaddbuf(sc, txq, bf_head);
}
static void ath_tx_complete_buf ( struct ath_softc sc,
struct ath_buf bf,
struct ath_txq txq,
struct list_head bf_q,
struct ath_tx_status ts,
int  txok,
int  sendbar 
) [static]

Definition at line 623 of file ath9k_xmit.c.

References ATH_TX_BAR, ath_tx_complete(), ATH_TX_ERROR, ATH_TX_XRETRY, ath_buf::bf_buf_addr, bf_isxretried, ath_buf::bf_mpdu, list_splice_tail_init, NULL, ath_softc::tx, and ath_tx::txbuf.

Referenced by ath_draintxq(), and ath_tx_processq().

{
        struct io_buffer *iob = bf->bf_mpdu;
        int tx_flags = 0;

        if (sendbar)
                tx_flags = ATH_TX_BAR;

        if (!txok) {
                tx_flags |= ATH_TX_ERROR;

                if (bf_isxretried(bf))
                        tx_flags |= ATH_TX_XRETRY;
        }

        bf->bf_buf_addr = 0;

        ath_tx_complete(sc, iob, tx_flags,
                        ts, txq);

        /* At this point, iob (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
         */
        list_splice_tail_init(bf_q, &sc->tx.txbuf);
}
static void ath_tx_txqaddbuf ( struct ath_softc sc,
struct ath_txq txq,
struct list_head head 
) [static]

Definition at line 323 of file ath9k_xmit.c.

References ah, ath9k_hw_get_desc_link(), ath9k_hw_puttxbuf(), ath9k_hw_txstart(), ath_txq::axq_depth, ath_txq::axq_link, ath_txq::axq_q, ath_txq::axq_qnum, ath_buf::bf_daddr, ath_buf::bf_desc, ath_buf::bf_lastbf, DBGIO, ito64, ath_buf::list, list_empty, list_first_entry, list_splice_tail_init, NULL, and ath_softc::sc_ah.

Referenced by ath_tx_send_normal().

{
        struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf;

        /*
         * Insert the frame on the outbound list and
         * pass it on to the hardware.
         */

        if (list_empty(head))
                return;

        bf = list_first_entry(head, struct ath_buf, list);

        DBGIO("ath9k: "
                "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);

        list_splice_tail_init(head, &txq->axq_q);

        if (txq->axq_link == NULL) {
                ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
                DBGIO("ath9k: TXDP[%d] = %llx (%p)\n",
                        txq->axq_qnum, ito64(bf->bf_daddr),
                        bf->bf_desc);
        } else {
                *txq->axq_link = bf->bf_daddr;
                DBGIO("ath9k: "
                        "link[%d] (%p)=%llx (%p)\n",
                        txq->axq_qnum, txq->axq_link,
                        ito64(bf->bf_daddr), bf->bf_desc);
        }
        ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
                               &txq->axq_link);
        ath9k_hw_txstart(ah, txq->axq_qnum);

        txq->axq_depth++;
}
static void ath_buf_set_rate ( struct ath_softc sc,
struct ath_buf bf,
int  len 
) [static]

Definition at line 421 of file ath9k_xmit.c.

References __unused, ath9k_hw_common(), ath9k_hw_computetxtime(), ath9k_hw_set11n_ratescenario(), ATH9K_RATESERIES_RTS_CTS, ATH9K_TXDESC_CTSENA, ATH9K_TXDESC_RTSENA, ath_txchainmask_reduction(), ATH_TXMAXTRY, ath_buf::bf_desc, bf_isaggr, ath_buf::bf_lastbf, ath_buf::bf_state, ath_buf_state::bfs_paprd, ath9k_legacy_rate::bitrate, ath_hw::caps, net80211_device::channel, CHANNEL_CCK, CHANNEL_OFDM, net80211_device::channels, ath9k_11n_rate_series::ChSel, common, ath_softc::dev, flags, ath9k_legacy_rate::flags, ath_softc::hw_rix, ath9k_legacy_rate::hw_value, ath9k_legacy_rate::hw_value_short, IEEE80211_TX_RC_USE_SHORT_PREAMBLE, memset(), NET80211_BAND_2GHZ, phy, ath9k_11n_rate_series::PktDuration, ath9k_11n_rate_series::Rate, ath9k_11n_rate_series::RateFlags, ath_softc::rates, ath9k_hw_capabilities::rts_aggr_limit, ath_softc::sc_ah, ath_softc::sc_flags, SC_OP_PREAMBLE_SHORT, SC_OP_PROTECT_ENABLE, ath9k_11n_rate_series::Tries, and ath_common::tx_chainmask.

Referenced by ath_tx_send_normal().

{
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath9k_11n_rate_series series[4];
        const struct ath9k_legacy_rate *rate;
        int i, flags = 0;
        u8 rix = 0, ctsrate = 0;
        int is_pspoll;

        memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);

        is_pspoll = 0;

        /*
         * 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 = &sc->rates[sc->hw_rix];
        ctsrate = rate->hw_value;
        if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
                ctsrate |= rate->hw_value_short;

        for (i = 0; i < 4; i++) {
                int is_40 __unused, is_sgi __unused, is_sp;
                int phy;

                rix = sc->hw_rix;
                series[i].Tries = ATH_TXMAXTRY;

                if (sc->sc_flags & SC_OP_PROTECT_ENABLE) {
                        series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS;
                        flags |= ATH9K_TXDESC_CTSENA;
                }

                is_sp = !!(rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE);

                /* legacy rates */
                if ((sc->dev->channels + sc->dev->channel)->band == NET80211_BAND_2GHZ)
                        phy = CHANNEL_CCK;
                else
                        phy = CHANNEL_OFDM;

                series[i].Rate = rate->hw_value;
                if (rate->hw_value_short && (sc->sc_flags & SC_OP_PREAMBLE_SHORT)) {
                        if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
                                series[i].Rate |= rate->hw_value_short;
                } else {
                        is_sp = 0;
                }

                if (bf->bf_state.bfs_paprd)
                        series[i].ChSel = common->tx_chainmask;
                else
                        series[i].ChSel = ath_txchainmask_reduction(sc,
                                        common->tx_chainmask, series[i].Rate);

                series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
                        phy, rate->bitrate * 100, len, rix, is_sp);
        }

        /* For AR5416 - RTS cannot be followed by a frame larger than 8K */
        if (bf_isaggr(bf) && (len > sc->sc_ah->caps.rts_aggr_limit))
                flags &= ~ATH9K_TXDESC_RTSENA;

        /* ATH9K_TXDESC_RTSENA and ATH9K_TXDESC_CTSENA are mutually exclusive. */
        if (flags & ATH9K_TXDESC_RTSENA)
                flags &= ~ATH9K_TXDESC_CTSENA;

        /* set dur_update_en for l-sig computation except for PS-Poll frames */
        ath9k_hw_set11n_ratescenario(sc->sc_ah, bf->bf_desc,
                                     bf->bf_lastbf->bf_desc,
                                     !is_pspoll, ctsrate,
                                     0, series, 4, flags);

}
static void ath_tx_queue_tid ( struct ath_txq txq,
struct ath_atx_tid tid 
) [static]

Definition at line 63 of file ath9k_xmit.c.

References ath_atx_tid::ac, ath_txq::axq_acq, ath_atx_ac::list, ath_atx_tid::list, list_add_tail, ath_atx_tid::paused, ath_atx_ac::sched, ath_atx_tid::sched, and ath_atx_ac::tid_q.

Referenced by ath_txq_schedule().

{
        struct ath_atx_ac *ac = tid->ac;

        if (tid->paused)
                return;

        if (tid->sched)
                return;

        tid->sched = 1;
        list_add_tail(&tid->list, &ac->tid_q);

        if (ac->sched)
                return;

        ac->sched = 1;
        list_add_tail(&ac->list, &txq->axq_acq);
}
static struct ath_buf* ath_tx_get_buffer ( struct ath_softc sc) [static, read]

Definition at line 83 of file ath9k_xmit.c.

References ath_buf::list, list_del, list_empty, list_first_entry, NULL, ath_softc::tx, and ath_tx::txbuf.

Referenced by ath_tx_setup_buffer().

{
        struct ath_buf *bf = NULL;

        if (list_empty(&sc->tx.txbuf)) {
                return NULL;
        }

        bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list);
        list_del(&bf->list);

        return bf;
}
static void ath_tx_return_buffer ( struct ath_softc sc,
struct ath_buf bf 
) [static]

Definition at line 97 of file ath9k_xmit.c.

References ath_buf::list, list_add_tail, ath_softc::tx, and ath_tx::txbuf.

Referenced by ath_draintxq(), and ath_tx_processq().

{
        list_add_tail(&bf->list, &sc->tx.txbuf);
}
struct ath_txq* ath_txq_setup ( struct ath_softc sc,
int  qtype,
int  subtype 
) [read]

Definition at line 106 of file ath9k_xmit.c.

References ah, ARRAY_SIZE, ath9k_hw_releasetxqueue(), ath9k_hw_setuptxqueue(), ATH9K_TXQ_USEDEFAULT, ATH_TXFIFO_DEPTH, ATH_TXQ_AC_BE, ATH_TXQ_SETUP, ath_txq::axq_acq, ath_txq::axq_ampdu_depth, ath_txq::axq_depth, ath_txq::axq_link, ath_txq::axq_q, ath_txq::axq_qnum, ath_txq::axq_tx_inprogress, DBG, INIT_LIST_HEAD, ath_txq::mac80211_qnum, memset(), NULL, ath_softc::sc_ah, subtype, ath9k_tx_queue_info::tqi_aifs, ath9k_tx_queue_info::tqi_cwmax, ath9k_tx_queue_info::tqi_cwmin, ath9k_tx_queue_info::tqi_physCompBuf, ath9k_tx_queue_info::tqi_qflags, ath9k_tx_queue_info::tqi_subtype, ath_softc::tx, ath_tx::txq, ath_txq::txq_fifo, ath_txq::txq_fifo_pending, TXQ_FLAG_TXDESCINT_ENABLE, TXQ_FLAG_TXEOLINT_ENABLE, ath_txq::txq_headidx, ath_txq::txq_tailidx, ath_tx::txqsetup, and WME_AC_BE.

Referenced by ath9k_init_queues().

{
        struct ath_hw *ah = sc->sc_ah;
        struct ath9k_tx_queue_info qi;
        static const int subtype_txq_to_hwq[] = {
                [WME_AC_BE] = ATH_TXQ_AC_BE,
        };
        int axq_qnum, i;

        memset(&qi, 0, sizeof(qi));
        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;
        qi.tqi_physCompBuf = 0;

        /*
         * Enable interrupts only for EOL and DESC conditions.
         * We mark tx descriptors to receive a DESC interrupt
         * when a tx queue gets deep; otherwise waiting for the
         * EOL to reap descriptors.  Note that this is done to
         * reduce interrupt load and this only defers reaping
         * descriptors, never transmitting frames.  Aside from
         * reducing interrupts this also permits more concurrency.
         * The only potential downside is if the tx queue backs
         * up in which case the top half of the kernel may backup
         * due to a lack of tx descriptors.
         *
         * The UAPSD queue is an exception, since we take a desc-
         * based intr on the EOSP frames.
         */
        qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE |
                        TXQ_FLAG_TXDESCINT_ENABLE;

        axq_qnum = ath9k_hw_setuptxqueue(ah, qtype, &qi);
        if (axq_qnum == -1) {
                /*
                 * NB: don't print a message, this happens
                 * normally on parts with too few tx queues
                 */
                return NULL;
        }
        if ((unsigned int)axq_qnum >= ARRAY_SIZE(sc->tx.txq)) {
                DBG("ath9k: qnum %d out of range, max %zd!\n",
                        axq_qnum, ARRAY_SIZE(sc->tx.txq));
                ath9k_hw_releasetxqueue(ah, axq_qnum);
                return NULL;
        }
        if (!ATH_TXQ_SETUP(sc, axq_qnum)) {
                struct ath_txq *txq = &sc->tx.txq[axq_qnum];

                txq->axq_qnum = axq_qnum;
                txq->mac80211_qnum = -1;
                txq->axq_link = NULL;
                INIT_LIST_HEAD(&txq->axq_q);
                INIT_LIST_HEAD(&txq->axq_acq);
                txq->axq_depth = 0;
                txq->axq_ampdu_depth = 0;
                txq->axq_tx_inprogress = 0;
                sc->tx.txqsetup |= 1<<axq_qnum;

                txq->txq_headidx = txq->txq_tailidx = 0;
                for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
                        INIT_LIST_HEAD(&txq->txq_fifo[i]);
                INIT_LIST_HEAD(&txq->txq_fifo_pending);
        }
        return &sc->tx.txq[axq_qnum];
}
void ath_draintxq ( struct ath_softc sc,
struct ath_txq txq,
int retry_tx  __unused 
)

Definition at line 181 of file ath9k_xmit.c.

References __unused, ath_tx_complete_buf(), ath_tx_return_buffer(), ath_txq::axq_depth, ath_txq::axq_link, ath_txq::axq_q, ath_txq::axq_tx_inprogress, ath_buf::bf_lastbf, ath_buf::bf_stale, INIT_LIST_HEAD, ath_buf::list, list_cut_position, list_del, list_empty, list_first_entry, memset(), and NULL.

Referenced by ath_drain_all_txq().

{
        struct ath_buf *bf, *lastbf __unused;
        struct list_head bf_head;
        struct ath_tx_status ts;

        memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);

        for (;;) {
                if (list_empty(&txq->axq_q)) {
                        txq->axq_link = NULL;
                        break;
                }
                bf = list_first_entry(&txq->axq_q, struct ath_buf,
                                      list);

                if (bf->bf_stale) {
                        list_del(&bf->list);

                        ath_tx_return_buffer(sc, bf);
                        continue;
                }

                lastbf = bf->bf_lastbf;

                list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);

                txq->axq_depth--;
                ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
        }

        txq->axq_tx_inprogress = 0;
}
int ath_drain_all_txq ( struct ath_softc sc,
int  retry_tx 
)

Definition at line 216 of file ath9k_xmit.c.

References ah, ath9k_hw_abort_tx_dma(), ath9k_hw_numtxpending(), ATH9K_NUM_TX_QUEUES, ath_draintxq(), ATH_TXQ_SETUP, ath_txq::axq_qnum, DBG, ath_softc::sc_ah, ath_softc::sc_flags, SC_OP_INVALID, ath_txq::stopped, ath_softc::tx, and ath_tx::txq.

Referenced by ath9k_stop(), ath_radio_disable(), ath_reset(), and ath_set_channel().

{
        struct ath_hw *ah = sc->sc_ah;
        struct ath_txq *txq;
        int i, npend = 0;

        if (sc->sc_flags & SC_OP_INVALID)
                return 1;

        ath9k_hw_abort_tx_dma(ah);

        /* Check if any queue remains active */
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
                if (!ATH_TXQ_SETUP(sc, i))
                        continue;

                npend += ath9k_hw_numtxpending(ah, sc->tx.txq[i].axq_qnum);
        }

        if (npend)
                DBG("ath9k: Failed to stop TX DMA!\n");

        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
                if (!ATH_TXQ_SETUP(sc, i))
                        continue;

                /*
                 * The caller will resume queues with ieee80211_wake_queues.
                 * Mark the queue as not stopped to prevent ath_tx_complete
                 * from waking the queue too early.
                 */
                txq = &sc->tx.txq[i];
                txq->stopped = 0;
                ath_draintxq(sc, txq, retry_tx);
        }

        return !npend;
}
void ath_tx_cleanupq ( struct ath_softc sc,
struct ath_txq txq 
)
void ath_txq_schedule ( struct ath_softc *sc  __unused,
struct ath_txq txq 
)

Definition at line 264 of file ath9k_xmit.c.

References ATH_AGGR_MIN_QDEPTH, ath_tx_queue_tid(), ath_txq::axq_acq, ath_txq::axq_ampdu_depth, ath_atx_tid::buf_q, ath_atx_ac::list, ath_atx_tid::list, list_add_tail, list_del, list_empty, list_entry, list_first_entry, list_for_each_entry_safe, ath_atx_tid::paused, list_head::prev, ath_atx_ac::sched, ath_atx_tid::sched, tid, and ath_atx_ac::tid_q.

{
        struct ath_atx_ac *ac, *ac_tmp, *last_ac;
        struct ath_atx_tid *tid, *last_tid;

        if (list_empty(&txq->axq_acq) ||
            txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
                return;

        ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac, list);
        last_ac = list_entry(txq->axq_acq.prev, struct ath_atx_ac, list);

        list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) {
                last_tid = list_entry(ac->tid_q.prev, struct ath_atx_tid, list);
                list_del(&ac->list);
                ac->sched = 0;

                while (!list_empty(&ac->tid_q)) {
                        tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
                                               list);
                        list_del(&tid->list);
                        tid->sched = 0;

                        if (tid->paused)
                                continue;

                        /*
                         * add tid to round-robin queue if more frames
                         * are pending for the tid
                         */
                        if (!list_empty(&tid->buf_q))
                                ath_tx_queue_tid(txq, tid);

                        if (tid == last_tid ||
                            txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
                                break;
                }

                if (!list_empty(&ac->tid_q)) {
                        if (!ac->sched) {
                                ac->sched = 1;
                                list_add_tail(&ac->list, &txq->axq_acq);
                        }
                }

                if (ac == last_ac ||
                    txq->axq_ampdu_depth >= ATH_AGGR_MIN_QDEPTH)
                        return;
        }
}
static enum ath9k_pkt_type get_hw_packet_type ( struct io_buffer iob) [static]
static int setup_tx_flags ( struct io_buffer *iob  __unused) [static]

Definition at line 400 of file ath9k_xmit.c.

References ATH9K_TXDESC_INTREQ, and flags.

Referenced by ath_tx_setup_buffer().

{
        int flags = 0;

        flags |= ATH9K_TXDESC_INTREQ;

        return flags;
}
u8 ath_txchainmask_reduction ( struct ath_softc sc,
u8  chainmask,
u32  rate 
)

Definition at line 409 of file ath9k_xmit.c.

References ah, CHANNEL_5GHZ, ath9k_channel::channelFlags, ath_hw::curchan, ath_softc::sc_ah, ath_softc::sc_flags, and SC_OP_ENABLE_APM.

Referenced by ath_buf_set_rate().

{
        struct ath_hw *ah = sc->sc_ah;
        struct ath9k_channel *curchan = ah->curchan;
        if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
                        (curchan->channelFlags & CHANNEL_5GHZ) &&
                        (chainmask == 0x7) && (rate < 0x90))
                return 0x3;
        else
                return chainmask;
}
static struct ath_buf* ath_tx_setup_buffer ( struct net80211_device dev,
struct ath_txq txq,
struct io_buffer iob 
) [static, read]

Definition at line 498 of file ath9k_xmit.c.

References ah, net80211_crypto::algorithm, ath9k_hw_filltxdesc(), ath9k_hw_set11n_txdesc(), ath9k_hw_set_desc_link(), ATH9K_KEY_TYPE_AES, ATH9K_KEY_TYPE_CLEAR, ATH9K_KEY_TYPE_TKIP, ATH9K_KEY_TYPE_WEP, ATH9K_TXKEYIX_INVALID, ath_tx_get_buffer(), ATH_TXBUF_RESET, ath_txq::axq_qnum, ath_buf::bf_buf_addr, ath_buf::bf_desc, ath_buf::bf_flags, ath_buf::bf_mpdu, net80211_device::crypto, io_buffer::data, DBG, ds, FCS_LEN, get_hw_packet_type(), iob_len(), MAX_RATE_POWER, NET80211_CRYPT_CCMP, NET80211_CRYPT_NONE, NET80211_CRYPT_TKIP, NET80211_CRYPT_UNKNOWN, NET80211_CRYPT_WEP, NULL, net80211_device::priv, ath_softc::sc_ah, setup_tx_flags(), and virt_to_bus().

Referenced by ath_tx_start().

{
        struct ath_softc *sc = dev->priv;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf;
        struct ath_desc *ds;
        int frm_type;
        static const enum ath9k_key_type net80211_keytype_to_ath[] = {
                        [NET80211_CRYPT_NONE] = ATH9K_KEY_TYPE_CLEAR,
                        [NET80211_CRYPT_WEP] = ATH9K_KEY_TYPE_WEP,
                        [NET80211_CRYPT_TKIP] = ATH9K_KEY_TYPE_TKIP,
                        [NET80211_CRYPT_CCMP] = ATH9K_KEY_TYPE_AES,
                        [NET80211_CRYPT_UNKNOWN] = ATH9K_KEY_TYPE_CLEAR,
        };

        bf = ath_tx_get_buffer(sc);
        if (!bf) {
                DBG("ath9k: TX buffers are full\n");
                return NULL;
        }

        ATH_TXBUF_RESET(bf);

        bf->bf_flags = setup_tx_flags(iob);
        bf->bf_mpdu = iob;

        bf->bf_buf_addr = virt_to_bus(iob->data);

        frm_type = get_hw_packet_type(iob);

        ds = bf->bf_desc;
        ath9k_hw_set_desc_link(ah, ds, 0);

        ath9k_hw_set11n_txdesc(ah, ds, iob_len(iob) + FCS_LEN, frm_type, MAX_RATE_POWER,
                               ATH9K_TXKEYIX_INVALID, net80211_keytype_to_ath[dev->crypto->algorithm], bf->bf_flags);

        ath9k_hw_filltxdesc(ah, ds,
                            iob_len(iob),       /* segment length */
                            1,          /* first segment */
                            1,          /* last segment */
                            ds,         /* first descriptor */
                            bf->bf_buf_addr,
                            txq->axq_qnum);


        return bf;
}
static void ath_tx_start_dma ( struct ath_softc sc,
struct ath_buf bf,
struct ath_tx_control txctl 
) [static]
int ath_tx_start ( struct net80211_device dev,
struct io_buffer iob,
struct ath_tx_control txctl 
)

Definition at line 569 of file ath9k_xmit.c.

References ATH_MAX_QDEPTH, ath_tx_setup_buffer(), ath_tx_start_dma(), ENOMEM, ath_txq::pending_frames, net80211_device::priv, ath_txq::stopped, ath_softc::tx, ath_tx_control::txq, and ath_tx::txq_map.

Referenced by ath9k_tx().

{
        struct ath_softc *sc = dev->priv;
        struct ath_txq *txq = txctl->txq;
        struct ath_buf *bf;
        int q;

        /*
         * At this point, the vif, hw_key and sta pointers in the tx control
         * info are no longer valid (overwritten by the ath_frame_info data.
         */

        bf = ath_tx_setup_buffer(dev, txctl->txq, iob);
        if (!bf)
                return -ENOMEM;

        q = 0;
        if (txq == sc->tx.txq_map[q] &&
            ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
                txq->stopped = 1;
        }

        ath_tx_start_dma(sc, bf, txctl);

        return 0;
}
static void ath_tx_complete ( struct ath_softc sc,
struct io_buffer iob,
int tx_flags  __unused,
struct ath_tx_status ts,
struct ath_txq txq 
) [static]

Definition at line 601 of file ath9k_xmit.c.

References __unused, ATH9K_TXERR_MASK, ATH_MAX_QDEPTH, DBGIO, ath_softc::dev, EIO, net80211_tx_complete(), ath_txq::pending_frames, ath_txq::stopped, ath_tx_status::ts_longretry, ath_tx_status::ts_status, ath_softc::tx, and ath_tx::txq_map.

Referenced by ath_tx_complete_buf().

{
        struct net80211_device *dev = sc->dev;
        int q, padpos __unused, padsize __unused;

        DBGIO("ath9k: TX complete: iob: %p\n", iob);

        q = 0;
        if (txq == sc->tx.txq_map[q]) {
                if (--txq->pending_frames < 0)
                        txq->pending_frames = 0;

                if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
                        txq->stopped = 0;
                }
        }

        net80211_tx_complete(dev, iob, ts->ts_longretry,
                        (ts->ts_status & ATH9K_TXERR_MASK) ? EIO : 0);
}
static void ath_tx_processq ( struct ath_softc sc,
struct ath_txq txq 
) [static]

Definition at line 656 of file ath9k_xmit.c.

References ah, ath9k_hw_gettxbuf(), ath9k_hw_txprocdesc(), ATH9K_TXERR_MASK, ATH9K_TXERR_XRETRY, ath_tx_complete_buf(), ath_tx_return_buffer(), ath_txq_schedule(), ath_txq::axq_depth, ath_txq::axq_link, ath_txq::axq_q, ath_txq::axq_qnum, ath_txq::axq_tx_inprogress, ath_buf::bf_desc, ath_buf::bf_lastbf, ath_buf::bf_stale, ath_buf::bf_state, ath_buf_state::bf_type, BUF_XRETRY, DBGIO, ds, EINPROGRESS, INIT_LIST_HEAD, ath_buf::list, list_cut_position, list_del, list_empty, list_entry, list_first_entry, list_is_last, list_is_singular, memset(), list_head::next, NULL, list_head::prev, ath_softc::sc_ah, ath_softc::sc_flags, SC_OP_TXAGGR, status, and ath_tx_status::ts_status.

Referenced by ath_tx_tasklet().

{
        struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf, *lastbf, *bf_held = NULL;
        struct list_head bf_head;
        struct ath_desc *ds;
        struct ath_tx_status ts;
        int txok;
        int status;

        DBGIO("ath9k: tx queue %d (%x), link %p\n",
                txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
                txq->axq_link);

        for (;;) {
                if (list_empty(&txq->axq_q)) {
                        txq->axq_link = NULL;
                        if (sc->sc_flags & SC_OP_TXAGGR)
                                ath_txq_schedule(sc, txq);
                        break;
                }
                bf = list_first_entry(&txq->axq_q, struct ath_buf, list);

                /*
                 * There is a race condition that a BH gets scheduled
                 * after sw writes TxE and before hw re-load the last
                 * descriptor to get the newly chained one.
                 * Software must keep the last DONE descriptor as a
                 * holding descriptor - software does so by marking
                 * it with the STALE flag.
                 */
                bf_held = NULL;
                if (bf->bf_stale) {
                        bf_held = bf;
                        if (list_is_last(&bf_held->list, &txq->axq_q)) {
                                break;
                        } else {
                                bf = list_entry(bf_held->list.next,
                                                struct ath_buf, list);
                        }
                }

                lastbf = bf->bf_lastbf;
                ds = lastbf->bf_desc;

                memset(&ts, 0, sizeof(ts));
                status = ath9k_hw_txprocdesc(ah, ds, &ts);
                if (status == -EINPROGRESS) {
                        break;
                }

                /*
                 * Remove ath_buf's of the same transmit unit from txq,
                 * however leave the last descriptor back as the holding
                 * descriptor for hw.
                 */
                lastbf->bf_stale = 1;
                INIT_LIST_HEAD(&bf_head);
                if (!list_is_singular(&lastbf->list))
                        list_cut_position(&bf_head,
                                &txq->axq_q, lastbf->list.prev);

                txq->axq_depth--;
                txok = !(ts.ts_status & ATH9K_TXERR_MASK);
                txq->axq_tx_inprogress = 0;
                if (bf_held)
                        list_del(&bf_held->list);

                if (bf_held)
                        ath_tx_return_buffer(sc, bf_held);

                /*
                 * This frame is sent out as a single frame.
                 * Use hardware retry status for this frame.
                 */
                if (ts.ts_status & ATH9K_TXERR_XRETRY)
                        bf->bf_state.bf_type |= BUF_XRETRY;

                ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);

                if (sc->sc_flags & SC_OP_TXAGGR)
                        ath_txq_schedule(sc, txq);
        }
}
static void ath_tx_complete_poll_work ( struct ath_softc sc) [static]

Definition at line 741 of file ath9k_xmit.c.

References ATH9K_NUM_TX_QUEUES, ath_reset(), ATH_TX_COMPLETE_POLL_INT, ATH_TXQ_SETUP, ath_txq::axq_depth, ath_txq::axq_tx_inprogress, currticks(), DBG, TICKS_PER_SEC, ath_softc::tx, ath_softc::tx_complete_work_timer, and ath_tx::txq.

Referenced by ath_tx_init().

{
        struct ath_txq *txq;
        int i;
        int needreset = 0;

        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
                if (ATH_TXQ_SETUP(sc, i)) {
                        txq = &sc->tx.txq[i];
                        if (txq->axq_depth) {
                                if (txq->axq_tx_inprogress) {
                                        needreset = 1;
                                        break;
                                } else {
                                        txq->axq_tx_inprogress = 1;
                                }
                        }
                }

        if (needreset) {
                DBG("ath9k: "
                        "tx hung, resetting the chip\n");
                ath_reset(sc, 1);
        }

        sc->tx_complete_work_timer = ( currticks() * 1000 ) / TICKS_PER_SEC + ATH_TX_COMPLETE_POLL_INT;
}
void ath_tx_tasklet ( struct ath_softc sc)

Definition at line 771 of file ath9k_xmit.c.

References ath9k_hw_gettxintrtxqs(), ATH9K_NUM_TX_QUEUES, ath_tx_processq(), ATH_TXQ_SETUP, ath_softc::sc_ah, ath_softc::tx, and ath_tx::txq.

Referenced by ath9k_tasklet().

{
        int i;
        u32 qcumask = ((1 << ATH9K_NUM_TX_QUEUES) - 1);

        ath9k_hw_gettxintrtxqs(sc->sc_ah, &qcumask);

        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) {
                if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i)))
                        ath_tx_processq(sc, &sc->tx.txq[i]);
        }
}
int ath_tx_init ( struct ath_softc sc,
int  nbufs 
)

Definition at line 788 of file ath9k_xmit.c.

References ath_descdma_setup(), ath_tx_cleanup(), ath_tx_complete_poll_work(), DBG, error, ath_softc::tx, ath_softc::tx_complete_work, ath_tx::txbuf, and ath_tx::txdma.

Referenced by ath9k_init_device().

{
        int error = 0;

        error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf,
                                  "tx", nbufs, 1, 1);
        if (error != 0) {
                DBG("ath9k: "
                        "Failed to allocate tx descriptors: %d\n", error);
                goto err;
        }

        sc->tx_complete_work = ath_tx_complete_poll_work;

err:
        if (error != 0)
                ath_tx_cleanup(sc);

        return error;
}
void ath_tx_cleanup ( struct ath_softc sc)