Commit 2d42efc4 authored by Felix Fietkau's avatar Felix Fietkau Committed by John W. Linville

ath9k: store frame information used by aggregation inside the skb tx info

Since the pointers after the rates in the tx info cannot be used anymore
after frames have been queued, this area can be used to store information
that was previously stored in the ath_buf. With these changes, we can delay
the ath_buf assignment in the aggregation code until aggregates are formed.

That will not only make it possible to simplify DMA descriptor setup to
do less rewriting of uncached memory, but will also make it easier to
move aggregation out of the core of the ath9k tx path.
Signed-off-by: default avatarFelix Fietkau <nbd@openwrt.org>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 04caf863
...@@ -89,20 +89,16 @@ struct ath_config { ...@@ -89,20 +89,16 @@ struct ath_config {
* @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX) * @BUF_AMPDU: This buffer is an ampdu, as part of an aggregate (during TX)
* @BUF_AGGR: Indicates whether the buffer can be aggregated * @BUF_AGGR: Indicates whether the buffer can be aggregated
* (used in aggregation scheduling) * (used in aggregation scheduling)
* @BUF_RETRY: Indicates whether the buffer is retried
* @BUF_XRETRY: To denote excessive retries of the buffer * @BUF_XRETRY: To denote excessive retries of the buffer
*/ */
enum buffer_type { enum buffer_type {
BUF_AMPDU = BIT(2), BUF_AMPDU = BIT(2),
BUF_AGGR = BIT(3), BUF_AGGR = BIT(3),
BUF_RETRY = BIT(4),
BUF_XRETRY = BIT(5), BUF_XRETRY = BIT(5),
}; };
#define bf_retries bf_state.bfs_retries
#define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU) #define bf_isampdu(bf) (bf->bf_state.bf_type & BUF_AMPDU)
#define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR)
#define bf_isretried(bf) (bf->bf_state.bf_type & BUF_RETRY)
#define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY) #define bf_isxretried(bf) (bf->bf_state.bf_type & BUF_XRETRY)
#define ATH_TXSTATUS_RING_SIZE 64 #define ATH_TXSTATUS_RING_SIZE 64
...@@ -207,8 +203,15 @@ struct ath_atx_ac { ...@@ -207,8 +203,15 @@ struct ath_atx_ac {
struct list_head tid_q; struct list_head tid_q;
}; };
struct ath_frame_info {
int framelen;
u32 keyix;
enum ath9k_key_type keytype;
u8 retries;
u16 seqno;
};
struct ath_buf_state { struct ath_buf_state {
int bfs_retries;
u8 bf_type; u8 bf_type;
u8 bfs_paprd; u8 bfs_paprd;
enum ath9k_internal_frame_type bfs_ftype; enum ath9k_internal_frame_type bfs_ftype;
...@@ -260,9 +263,9 @@ struct ath_node { ...@@ -260,9 +263,9 @@ struct ath_node {
struct ath_tx_control { struct ath_tx_control {
struct ath_txq *txq; struct ath_txq *txq;
struct ath_node *an;
int if_id; int if_id;
enum ath9k_internal_frame_type frame_type; enum ath9k_internal_frame_type frame_type;
int frmlen;
u8 paprd; u8 paprd;
}; };
......
...@@ -50,7 +50,7 @@ static u16 bits_per_symbol[][2] = { ...@@ -50,7 +50,7 @@ static u16 bits_per_symbol[][2] = {
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct ath_atx_tid *tid,
struct list_head *bf_head, int frmlen); struct list_head *bf_head);
static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, 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_txq *txq, struct list_head *bf_q,
struct ath_tx_status *ts, int txok, int sendbar); struct ath_tx_status *ts, int txok, int sendbar);
...@@ -138,30 +138,12 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ...@@ -138,30 +138,12 @@ static void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
} }
static u16 ath_frame_seqno(struct sk_buff *skb) static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
return le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT;
}
static int ath_frame_len(struct sk_buff *skb)
{ {
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; BUILD_BUG_ON(sizeof(struct ath_frame_info) >
int frmlen = skb->len + FCS_LEN; sizeof(tx_info->rate_driver_data));
int padpos, padsize; return (struct ath_frame_info *) &tx_info->rate_driver_data[0];
/* Remove the padding size, if any */
padpos = ath9k_cmn_padpos(hdr->frame_control);
padsize = padpos & 3;
if (padsize && skb->len > padpos + padsize)
frmlen -= padsize;
if (tx_info->control.hw_key)
frmlen += tx_info->control.hw_key->icv_len;
return frmlen;
} }
static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
...@@ -170,6 +152,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ...@@ -170,6 +152,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
struct ath_buf *bf; struct ath_buf *bf;
struct list_head bf_head; struct list_head bf_head;
struct ath_tx_status ts; struct ath_tx_status ts;
struct ath_frame_info *fi;
INIT_LIST_HEAD(&bf_head); INIT_LIST_HEAD(&bf_head);
...@@ -180,12 +163,12 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) ...@@ -180,12 +163,12 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
bf = list_first_entry(&tid->buf_q, struct ath_buf, list); bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
list_move_tail(&bf->list, &bf_head); list_move_tail(&bf->list, &bf_head);
if (bf_isretried(bf)) { fi = get_frame_info(bf->bf_mpdu);
ath_tx_update_baw(sc, tid, ath_frame_seqno(bf->bf_mpdu)); if (fi->retries) {
ath_tx_update_baw(sc, tid, fi->seqno);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
} else { } else {
ath_tx_send_normal(sc, txq, tid, &bf_head, ath_tx_send_normal(sc, txq, tid, &bf_head);
ath_frame_len(bf->bf_mpdu));
} }
} }
...@@ -237,7 +220,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, ...@@ -237,7 +220,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf; struct ath_buf *bf;
struct list_head bf_head; struct list_head bf_head;
struct ath_tx_status ts; struct ath_tx_status ts;
u16 bf_seqno; struct ath_frame_info *fi;
memset(&ts, 0, sizeof(ts)); memset(&ts, 0, sizeof(ts));
INIT_LIST_HEAD(&bf_head); INIT_LIST_HEAD(&bf_head);
...@@ -249,9 +232,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, ...@@ -249,9 +232,9 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
bf = list_first_entry(&tid->buf_q, struct ath_buf, list); bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
list_move_tail(&bf->list, &bf_head); list_move_tail(&bf->list, &bf_head);
bf_seqno = ath_frame_seqno(bf->bf_mpdu); fi = get_frame_info(bf->bf_mpdu);
if (bf_isretried(bf)) if (fi->retries)
ath_tx_update_baw(sc, tid, bf_seqno); ath_tx_update_baw(sc, tid, fi->seqno);
spin_unlock(&txq->axq_lock); spin_unlock(&txq->axq_lock);
ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0); ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
...@@ -263,16 +246,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, ...@@ -263,16 +246,15 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
} }
static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
struct ath_buf *bf) struct sk_buff *skb)
{ {
struct sk_buff *skb; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr; struct ieee80211_hdr *hdr;
bf->bf_state.bf_type |= BUF_RETRY;
bf->bf_retries++;
TX_STAT_INC(txq->axq_qnum, a_retries); TX_STAT_INC(txq->axq_qnum, a_retries);
if (tx_info->control.rates[4].count++ > 0)
return;
skb = bf->bf_mpdu;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY); hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_RETRY);
} }
...@@ -326,6 +308,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, ...@@ -326,6 +308,7 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
struct ath_tx_status *ts, int txok, struct ath_tx_status *ts, int txok,
int *nframes, int *nbad) int *nframes, int *nbad)
{ {
struct ath_frame_info *fi;
u16 seq_st = 0; u16 seq_st = 0;
u32 ba[WME_BA_BMP_SIZE >> 5]; u32 ba[WME_BA_BMP_SIZE >> 5];
int ba_index; int ba_index;
...@@ -341,7 +324,8 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf, ...@@ -341,7 +324,8 @@ static void ath_tx_count_frames(struct ath_softc *sc, struct ath_buf *bf,
} }
while (bf) { while (bf) {
ba_index = ATH_BA_INDEX(seq_st, ath_frame_seqno(bf->bf_mpdu)); fi = get_frame_info(bf->bf_mpdu);
ba_index = ATH_BA_INDEX(seq_st, fi->seqno);
(*nframes)++; (*nframes)++;
if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index))) if (!txok || (isaggr && !ATH_BA_ISSET(ba, ba_index)))
...@@ -370,7 +354,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -370,7 +354,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; int isaggr, txfail, txpending, sendbar = 0, needreset = 0, nbad = 0;
bool rc_update = true; bool rc_update = true;
struct ieee80211_tx_rate rates[4]; struct ieee80211_tx_rate rates[4];
u16 bf_seqno; struct ath_frame_info *fi;
int nframes; int nframes;
u8 tidno; u8 tidno;
...@@ -448,9 +432,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -448,9 +432,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
skb = bf->bf_mpdu; skb = bf->bf_mpdu;
tx_info = IEEE80211_SKB_CB(skb); tx_info = IEEE80211_SKB_CB(skb);
bf_seqno = ath_frame_seqno(skb); fi = get_frame_info(skb);
if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, bf_seqno))) { if (ATH_BA_ISSET(ba, ATH_BA_INDEX(seq_st, fi->seqno))) {
/* transmit completion, subframe is /* transmit completion, subframe is
* acked by block ack */ * acked by block ack */
acked_cnt++; acked_cnt++;
...@@ -459,8 +443,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -459,8 +443,8 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
acked_cnt++; acked_cnt++;
} else { } else {
if (!(tid->state & AGGR_CLEANUP) && retry) { if (!(tid->state & AGGR_CLEANUP) && retry) {
if (bf->bf_retries < ATH_MAX_SW_RETRIES) { if (fi->retries < ATH_MAX_SW_RETRIES) {
ath_tx_set_retry(sc, txq, bf); ath_tx_set_retry(sc, txq, bf->bf_mpdu);
txpending = 1; txpending = 1;
} else { } else {
bf->bf_state.bf_type |= BUF_XRETRY; bf->bf_state.bf_type |= BUF_XRETRY;
...@@ -498,7 +482,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -498,7 +482,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
* block-ack window * block-ack window
*/ */
spin_lock_bh(&txq->axq_lock); spin_lock_bh(&txq->axq_lock);
ath_tx_update_baw(sc, tid, bf_seqno); ath_tx_update_baw(sc, tid, fi->seqno);
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) { if (rc_update && (acked_cnt == 1 || txfail_cnt == 1)) {
...@@ -525,8 +509,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -525,8 +509,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
*/ */
if (!tbf) { if (!tbf) {
spin_lock_bh(&txq->axq_lock); spin_lock_bh(&txq->axq_lock);
ath_tx_update_baw(sc, tid, ath_tx_update_baw(sc, tid, fi->seqno);
bf_seqno);
spin_unlock_bh(&txq->axq_lock); spin_unlock_bh(&txq->axq_lock);
bf->bf_state.bf_type |= bf->bf_state.bf_type |=
...@@ -666,6 +649,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, ...@@ -666,6 +649,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
u16 minlen; u16 minlen;
u8 flags, rix; u8 flags, rix;
int width, streams, half_gi, ndelim, mindelim; int width, streams, half_gi, ndelim, mindelim;
struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
/* Select standard number of delimiters based on frame length alone */ /* Select standard number of delimiters based on frame length alone */
ndelim = ATH_AGGR_GET_NDELIM(frmlen); ndelim = ATH_AGGR_GET_NDELIM(frmlen);
...@@ -676,7 +660,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid, ...@@ -676,7 +660,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, struct ath_atx_tid *tid,
* TODO - this could be improved to be dependent on the rate. * TODO - this could be improved to be dependent on the rate.
* The hardware can keep up at lower rates, but not higher rates * The hardware can keep up at lower rates, but not higher rates
*/ */
if (tx_info->control.hw_key) if (fi->keyix != ATH9K_TXKEYIX_INVALID)
ndelim += ATH_AGGR_ENCRYPTDELIM; ndelim += ATH_AGGR_ENCRYPTDELIM;
/* /*
...@@ -730,17 +714,16 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, ...@@ -730,17 +714,16 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
al_delta, h_baw = tid->baw_size / 2; al_delta, h_baw = tid->baw_size / 2;
enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE;
struct ieee80211_tx_info *tx_info; struct ieee80211_tx_info *tx_info;
int frmlen; struct ath_frame_info *fi;
u16 bf_seqno;
bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list); bf_first = list_first_entry(&tid->buf_q, struct ath_buf, list);
do { do {
bf = list_first_entry(&tid->buf_q, struct ath_buf, list); bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
bf_seqno = ath_frame_seqno(bf->bf_mpdu); fi = get_frame_info(bf->bf_mpdu);
/* do not step over block-ack window */ /* do not step over block-ack window */
if (!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno)) { if (!BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno)) {
status = ATH_AGGR_BAW_CLOSED; status = ATH_AGGR_BAW_CLOSED;
break; break;
} }
...@@ -751,8 +734,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, ...@@ -751,8 +734,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
} }
/* do not exceed aggregation limit */ /* do not exceed aggregation limit */
frmlen = ath_frame_len(bf->bf_mpdu); al_delta = ATH_AGGR_DELIM_SZ + fi->framelen;
al_delta = ATH_AGGR_DELIM_SZ + frmlen;
if (nframes && if (nframes &&
(aggr_limit < (al + bpad + al_delta + prev_al))) { (aggr_limit < (al + bpad + al_delta + prev_al))) {
...@@ -779,15 +761,15 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, ...@@ -779,15 +761,15 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc,
* Get the delimiters needed to meet the MPDU * Get the delimiters needed to meet the MPDU
* density for this node. * density for this node.
*/ */
ndelim = ath_compute_num_delims(sc, tid, bf_first, frmlen); ndelim = ath_compute_num_delims(sc, tid, bf_first, fi->framelen);
bpad = PADBYTES(al_delta) + (ndelim << 2); bpad = PADBYTES(al_delta) + (ndelim << 2);
bf->bf_next = NULL; bf->bf_next = NULL;
ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0); ath9k_hw_set_desc_link(sc->sc_ah, bf->bf_desc, 0);
/* link buffers of this frame to the aggregate */ /* link buffers of this frame to the aggregate */
if (!bf_isretried(bf)) if (!fi->retries)
ath_tx_addto_baw(sc, tid, bf_seqno); ath_tx_addto_baw(sc, tid, fi->seqno);
ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim); ath9k_hw_set11n_aggr_middle(sc->sc_ah, bf->bf_desc, ndelim);
list_move_tail(&bf->list, bf_q); list_move_tail(&bf->list, bf_q);
if (bf_prev) { if (bf_prev) {
...@@ -810,6 +792,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -810,6 +792,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
{ {
struct ath_buf *bf; struct ath_buf *bf;
enum ATH_AGGR_STATUS status; enum ATH_AGGR_STATUS status;
struct ath_frame_info *fi;
struct list_head bf_q; struct list_head bf_q;
int aggr_len; int aggr_len;
...@@ -833,9 +816,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, ...@@ -833,9 +816,11 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
/* if only one frame, send as non-aggregate */ /* if only one frame, send as non-aggregate */
if (bf == bf->bf_lastbf) { if (bf == bf->bf_lastbf) {
fi = get_frame_info(bf->bf_mpdu);
bf->bf_state.bf_type &= ~BUF_AGGR; bf->bf_state.bf_type &= ~BUF_AGGR;
ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc); ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
ath_buf_set_rate(sc, bf, ath_frame_len(bf->bf_mpdu)); ath_buf_set_rate(sc, bf, fi->framelen);
ath_tx_txqaddbuf(sc, txq, &bf_q); ath_tx_txqaddbuf(sc, txq, &bf_q);
continue; continue;
} }
...@@ -1346,12 +1331,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, ...@@ -1346,12 +1331,11 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
struct ath_buf *bf, struct ath_tx_control *txctl) struct ath_buf *bf, struct ath_tx_control *txctl)
{ {
struct ath_frame_info *fi = get_frame_info(bf->bf_mpdu);
struct list_head bf_head; struct list_head bf_head;
u16 bf_seqno;
bf->bf_state.bf_type |= BUF_AMPDU; bf->bf_state.bf_type |= BUF_AMPDU;
TX_STAT_INC(txctl->txq->axq_qnum, a_queued); TX_STAT_INC(txctl->txq->axq_qnum, a_queued);
bf_seqno = ath_frame_seqno(bf->bf_mpdu);
/* /*
* Do not queue to h/w when any of the following conditions is true: * Do not queue to h/w when any of the following conditions is true:
...@@ -1361,7 +1345,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, ...@@ -1361,7 +1345,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
* - h/w queue depth exceeds low water mark * - h/w queue depth exceeds low water mark
*/ */
if (!list_empty(&tid->buf_q) || tid->paused || if (!list_empty(&tid->buf_q) || tid->paused ||
!BAW_WITHIN(tid->seq_start, tid->baw_size, bf_seqno) || !BAW_WITHIN(tid->seq_start, tid->baw_size, fi->seqno) ||
txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) {
/* /*
* Add this frame to software queue for scheduling later * Add this frame to software queue for scheduling later
...@@ -1376,19 +1360,20 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, ...@@ -1376,19 +1360,20 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
list_add(&bf->list, &bf_head); list_add(&bf->list, &bf_head);
/* Add sub-frame to BAW */ /* Add sub-frame to BAW */
if (!bf_isretried(bf)) if (!fi->retries)
ath_tx_addto_baw(sc, tid, bf_seqno); ath_tx_addto_baw(sc, tid, fi->seqno);
/* Queue to h/w without aggregation */ /* Queue to h/w without aggregation */
bf->bf_lastbf = bf; bf->bf_lastbf = bf;
ath_buf_set_rate(sc, bf, txctl->frmlen); ath_buf_set_rate(sc, bf, fi->framelen);
ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
} }
static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
struct ath_atx_tid *tid, struct ath_atx_tid *tid,
struct list_head *bf_head, int frmlen) struct list_head *bf_head)
{ {
struct ath_frame_info *fi;
struct ath_buf *bf; struct ath_buf *bf;
bf = list_first_entry(bf_head, struct ath_buf, list); bf = list_first_entry(bf_head, struct ath_buf, list);
...@@ -1399,7 +1384,8 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, ...@@ -1399,7 +1384,8 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
INCR(tid->seq_start, IEEE80211_SEQ_MAX); INCR(tid->seq_start, IEEE80211_SEQ_MAX);
bf->bf_lastbf = bf; bf->bf_lastbf = bf;
ath_buf_set_rate(sc, bf, frmlen); fi = get_frame_info(bf->bf_mpdu);
ath_buf_set_rate(sc, bf, fi->framelen);
ath_tx_txqaddbuf(sc, txq, bf_head); ath_tx_txqaddbuf(sc, txq, bf_head);
TX_STAT_INC(txq->axq_qnum, queued); TX_STAT_INC(txq->axq_qnum, queued);
} }
...@@ -1427,30 +1413,49 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) ...@@ -1427,30 +1413,49 @@ static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
return htype; return htype;
} }
static void assign_aggr_tid_seqno(struct sk_buff *skb) static void setup_frame_info(struct ieee80211_hw *hw, struct sk_buff *skb,
int framelen)
{ {
struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(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 *hdr;
struct ath_frame_info *fi = get_frame_info(skb);
struct ath_node *an; struct ath_node *an;
struct ath_atx_tid *tid; struct ath_atx_tid *tid;
__le16 fc; enum ath9k_key_type keytype;
u16 seqno = 0;
u8 tidno; u8 tidno;
if (!tx_info->control.sta) keytype = ath9k_cmn_get_hw_crypto_keytype(skb);
return;
an = (struct ath_node *)tx_info->control.sta->drv_priv;
hdr = (struct ieee80211_hdr *)skb->data; hdr = (struct ieee80211_hdr *)skb->data;
fc = hdr->frame_control; if (sta && ieee80211_is_data_qos(hdr->frame_control) &&
tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK; conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR)) {
/* an = (struct ath_node *) sta->drv_priv;
* Override seqno set by upper layer with the one tidno = ieee80211_get_qos_ctl(hdr)[0] & IEEE80211_QOS_CTL_TID_MASK;
* in tx aggregation state.
*/ /*
tid = ATH_AN_2_TID(an, tidno); * Override seqno set by upper layer with the one
hdr->seq_ctrl = cpu_to_le16(tid->seq_next << IEEE80211_SEQ_SEQ_SHIFT); * in tx aggregation state.
INCR(tid->seq_next, IEEE80211_SEQ_MAX); */
tid = ATH_AN_2_TID(an, tidno);
seqno = tid->seq_next;
hdr->seq_ctrl = cpu_to_le16(seqno << IEEE80211_SEQ_SEQ_SHIFT);
INCR(tid->seq_next, IEEE80211_SEQ_MAX);
}
memset(fi, 0, sizeof(*fi));
if (hw_key)
fi->keyix = hw_key->hw_key_idx;
else
fi->keyix = ATH9K_TXKEYIX_INVALID;
fi->keytype = keytype;
fi->framelen = framelen;
fi->seqno = seqno;
} }
static int setup_tx_flags(struct sk_buff *skb) static int setup_tx_flags(struct sk_buff *skb)
...@@ -1609,18 +1614,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len) ...@@ -1609,18 +1614,15 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
struct ath_txq *txq, struct ath_txq *txq,
struct sk_buff *skb, int frmlen) struct sk_buff *skb)
{ {
struct ath_wiphy *aphy = hw->priv; struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc; struct ath_softc *sc = aphy->sc;
struct ath_hw *ah = sc->sc_ah; struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(sc->sc_ah); struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ath_frame_info *fi = get_frame_info(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb;
struct ath_buf *bf; struct ath_buf *bf;
struct ath_desc *ds; struct ath_desc *ds;
enum ath9k_key_type keytype;
u32 keyix;
int frm_type; int frm_type;
bf = ath_tx_get_buffer(sc); bf = ath_tx_get_buffer(sc);
...@@ -1631,10 +1633,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ...@@ -1631,10 +1633,6 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
ATH_TXBUF_RESET(bf); ATH_TXBUF_RESET(bf);
if (ieee80211_is_data_qos(hdr->frame_control) &&
conf_is_ht(&hw->conf) && (sc->sc_flags & SC_OP_TXAGGR))
assign_aggr_tid_seqno(skb);
bf->aphy = aphy; bf->aphy = aphy;
bf->bf_flags = setup_tx_flags(skb); bf->bf_flags = setup_tx_flags(skb);
bf->bf_mpdu = skb; bf->bf_mpdu = skb;
...@@ -1655,14 +1653,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw, ...@@ -1655,14 +1653,8 @@ static struct ath_buf *ath_tx_setup_buffer(struct ieee80211_hw *hw,
ds = bf->bf_desc; ds = bf->bf_desc;
ath9k_hw_set_desc_link(ah, ds, 0); ath9k_hw_set_desc_link(ah, ds, 0);
keytype = ath9k_cmn_get_hw_crypto_keytype(skb); ath9k_hw_set11n_txdesc(ah, ds, fi->framelen, frm_type, MAX_RATE_POWER,
if (tx_info->control.hw_key) fi->keyix, fi->keytype, bf->bf_flags);
keyix = tx_info->control.hw_key->hw_key_idx;
else
keyix = ATH9K_TXKEYIX_INVALID;
ath9k_hw_set11n_txdesc(ah, ds, frmlen, frm_type, MAX_RATE_POWER,
keyix, keytype, bf->bf_flags);
ath9k_hw_filltxdesc(ah, ds, ath9k_hw_filltxdesc(ah, ds,
skb->len, /* segment length */ skb->len, /* segment length */
...@@ -1683,18 +1675,16 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, ...@@ -1683,18 +1675,16 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
struct sk_buff *skb = bf->bf_mpdu; struct sk_buff *skb = bf->bf_mpdu;
struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ath_node *an = NULL;
struct list_head bf_head; struct list_head bf_head;
struct ath_atx_tid *tid; struct ath_atx_tid *tid;
u8 tidno; u8 tidno;
spin_lock_bh(&txctl->txq->axq_lock); spin_lock_bh(&txctl->txq->axq_lock);
if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && tx_info->control.sta) { if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) && txctl->an) {
an = (struct ath_node *)tx_info->control.sta->drv_priv;
tidno = ieee80211_get_qos_ctl(hdr)[0] & tidno = ieee80211_get_qos_ctl(hdr)[0] &
IEEE80211_QOS_CTL_TID_MASK; IEEE80211_QOS_CTL_TID_MASK;
tid = ATH_AN_2_TID(an, tidno); tid = ATH_AN_2_TID(txctl->an, tidno);
WARN_ON(tid->ac->txq != txctl->txq); WARN_ON(tid->ac->txq != txctl->txq);
/* /*
...@@ -1713,7 +1703,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, ...@@ -1713,7 +1703,7 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc, ar9003_hw_set_paprd_txdesc(sc->sc_ah, bf->bf_desc,
bf->bf_state.bfs_paprd); bf->bf_state.bfs_paprd);
ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head, txctl->frmlen); ath_tx_send_normal(sc, txctl->txq, NULL, &bf_head);
} }
spin_unlock_bh(&txctl->txq->axq_lock); spin_unlock_bh(&txctl->txq->axq_lock);
...@@ -1725,6 +1715,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -1725,6 +1715,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
{ {
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sta *sta = info->control.sta;
struct ath_wiphy *aphy = hw->priv; struct ath_wiphy *aphy = hw->priv;
struct ath_softc *sc = aphy->sc; struct ath_softc *sc = aphy->sc;
struct ath_txq *txq = txctl->txq; struct ath_txq *txq = txctl->txq;
...@@ -1733,11 +1724,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -1733,11 +1724,10 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
int frmlen = skb->len + FCS_LEN; int frmlen = skb->len + FCS_LEN;
int q; int q;
txctl->an = (struct ath_node *)sta->drv_priv;
if (info->control.hw_key) if (info->control.hw_key)
frmlen += info->control.hw_key->icv_len; frmlen += info->control.hw_key->icv_len;
txctl->frmlen = frmlen;
/* /*
* As a temporary workaround, assign seq# here; this will likely need * As a temporary workaround, assign seq# here; this will likely need
* to be cleaned up to work better with Beacon transmission and virtual * to be cleaned up to work better with Beacon transmission and virtual
...@@ -1761,7 +1751,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb, ...@@ -1761,7 +1751,14 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
memmove(skb->data, skb->data + padsize, padpos); memmove(skb->data, skb->data + padsize, padpos);
} }
bf = ath_tx_setup_buffer(hw, txctl->txq, skb, frmlen); setup_frame_info(hw, skb, frmlen);
/*
* 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(hw, txctl->txq, skb);
if (unlikely(!bf)) if (unlikely(!bf))
return -ENOMEM; return -ENOMEM;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment