diff options
author | Sujith <Sujith.Manoharan@atheros.com> | 2009-03-09 00:01:57 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2009-03-16 18:09:38 -0400 |
commit | c37452b0687e5c8942dd4866f7c614105e6050c3 (patch) | |
tree | 4d1d44cbbf601973cf48b07c9e3f0b06e0f9f4f8 | |
parent | 9c81e8be236b7f1c94f9d055a97a83f84c81890f (diff) |
ath9k: Fix bug in TX aggregation
mac80211 expects the driver to fill in the starting
sequence number of an ADDBA request to initiate TX aggregation.
IEEE80211_TX_CTL_AMPDU would be set for frames only after a
successful ADDBA exchange, but we have to increment the
internal sequence counter for the normal(non-AMPDU) data frames proerly.
Signed-off-by: Sujith <Sujith.Manoharan@atheros.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/ath9k/xmit.c | 49 |
1 files changed, 33 insertions, 16 deletions
diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index a82d2ab7c3a0..f61ba2b7de71 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c | |||
@@ -55,9 +55,9 @@ static u32 bits_per_symbol[][2] = { | |||
55 | 55 | ||
56 | #define IS_HT_RATE(_rate) ((_rate) & 0x80) | 56 | #define IS_HT_RATE(_rate) ((_rate) & 0x80) |
57 | 57 | ||
58 | static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, | 58 | static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, |
59 | struct ath_atx_tid *tid, | 59 | struct ath_atx_tid *tid, |
60 | struct list_head *bf_head); | 60 | struct list_head *bf_head); |
61 | static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, | 61 | static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf, |
62 | struct list_head *bf_q, | 62 | struct list_head *bf_q, |
63 | int txok, int sendbar); | 63 | int txok, int sendbar); |
@@ -152,7 +152,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) | |||
152 | bf = list_first_entry(&tid->buf_q, struct ath_buf, list); | 152 | bf = list_first_entry(&tid->buf_q, struct ath_buf, list); |
153 | ASSERT(!bf_isretried(bf)); | 153 | ASSERT(!bf_isretried(bf)); |
154 | list_move_tail(&bf->list, &bf_head); | 154 | list_move_tail(&bf->list, &bf_head); |
155 | ath_tx_send_normal(sc, txq, tid, &bf_head); | 155 | ath_tx_send_ht_normal(sc, txq, tid, &bf_head); |
156 | } | 156 | } |
157 | 157 | ||
158 | spin_unlock_bh(&txq->axq_lock); | 158 | spin_unlock_bh(&txq->axq_lock); |
@@ -1238,9 +1238,9 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid, | |||
1238 | ath_tx_txqaddbuf(sc, txctl->txq, bf_head); | 1238 | ath_tx_txqaddbuf(sc, txctl->txq, bf_head); |
1239 | } | 1239 | } |
1240 | 1240 | ||
1241 | static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, | 1241 | static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq, |
1242 | struct ath_atx_tid *tid, | 1242 | struct ath_atx_tid *tid, |
1243 | struct list_head *bf_head) | 1243 | struct list_head *bf_head) |
1244 | { | 1244 | { |
1245 | struct ath_buf *bf; | 1245 | struct ath_buf *bf; |
1246 | 1246 | ||
@@ -1256,6 +1256,19 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, | |||
1256 | ath_tx_txqaddbuf(sc, txq, bf_head); | 1256 | ath_tx_txqaddbuf(sc, txq, bf_head); |
1257 | } | 1257 | } |
1258 | 1258 | ||
1259 | static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, | ||
1260 | struct list_head *bf_head) | ||
1261 | { | ||
1262 | struct ath_buf *bf; | ||
1263 | |||
1264 | bf = list_first_entry(bf_head, struct ath_buf, list); | ||
1265 | |||
1266 | bf->bf_lastbf = bf; | ||
1267 | bf->bf_nframes = 1; | ||
1268 | ath_buf_set_rate(sc, bf); | ||
1269 | ath_tx_txqaddbuf(sc, txq, bf_head); | ||
1270 | } | ||
1271 | |||
1259 | static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) | 1272 | static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) |
1260 | { | 1273 | { |
1261 | struct ieee80211_hdr *hdr; | 1274 | struct ieee80211_hdr *hdr; |
@@ -1522,8 +1535,7 @@ static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf, | |||
1522 | 1535 | ||
1523 | bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); | 1536 | bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); |
1524 | 1537 | ||
1525 | if ((conf_is_ht(&sc->hw->conf) && !is_pae(skb) && | 1538 | if (conf_is_ht(&sc->hw->conf) && !is_pae(skb)) |
1526 | (tx_info->flags & IEEE80211_TX_CTL_AMPDU))) | ||
1527 | bf->bf_state.bf_type |= BUF_HT; | 1539 | bf->bf_state.bf_type |= BUF_HT; |
1528 | 1540 | ||
1529 | bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); | 1541 | bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); |
@@ -1560,14 +1572,17 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1560 | { | 1572 | { |
1561 | struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; | 1573 | struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; |
1562 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); | 1574 | struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); |
1575 | struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; | ||
1563 | struct ath_node *an = NULL; | 1576 | struct ath_node *an = NULL; |
1564 | struct list_head bf_head; | 1577 | struct list_head bf_head; |
1565 | struct ath_desc *ds; | 1578 | struct ath_desc *ds; |
1566 | struct ath_atx_tid *tid; | 1579 | struct ath_atx_tid *tid; |
1567 | struct ath_hw *ah = sc->sc_ah; | 1580 | struct ath_hw *ah = sc->sc_ah; |
1568 | int frm_type; | 1581 | int frm_type; |
1582 | __le16 fc; | ||
1569 | 1583 | ||
1570 | frm_type = get_hw_packet_type(skb); | 1584 | frm_type = get_hw_packet_type(skb); |
1585 | fc = hdr->frame_control; | ||
1571 | 1586 | ||
1572 | INIT_LIST_HEAD(&bf_head); | 1587 | INIT_LIST_HEAD(&bf_head); |
1573 | list_add_tail(&bf->list, &bf_head); | 1588 | list_add_tail(&bf->list, &bf_head); |
@@ -1592,6 +1607,11 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1592 | an = (struct ath_node *)tx_info->control.sta->drv_priv; | 1607 | an = (struct ath_node *)tx_info->control.sta->drv_priv; |
1593 | tid = ATH_AN_2_TID(an, bf->bf_tidno); | 1608 | tid = ATH_AN_2_TID(an, bf->bf_tidno); |
1594 | 1609 | ||
1610 | if (!ieee80211_is_data_qos(fc)) { | ||
1611 | ath_tx_send_normal(sc, txctl->txq, &bf_head); | ||
1612 | goto tx_done; | ||
1613 | } | ||
1614 | |||
1595 | if (ath_aggr_query(sc, an, bf->bf_tidno)) { | 1615 | if (ath_aggr_query(sc, an, bf->bf_tidno)) { |
1596 | /* | 1616 | /* |
1597 | * Try aggregation if it's a unicast data frame | 1617 | * Try aggregation if it's a unicast data frame |
@@ -1603,17 +1623,14 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, | |||
1603 | * Send this frame as regular when ADDBA | 1623 | * Send this frame as regular when ADDBA |
1604 | * exchange is neither complete nor pending. | 1624 | * exchange is neither complete nor pending. |
1605 | */ | 1625 | */ |
1606 | ath_tx_send_normal(sc, txctl->txq, | 1626 | ath_tx_send_ht_normal(sc, txctl->txq, |
1607 | tid, &bf_head); | 1627 | tid, &bf_head); |
1608 | } | 1628 | } |
1609 | } else { | 1629 | } else { |
1610 | bf->bf_lastbf = bf; | 1630 | ath_tx_send_normal(sc, txctl->txq, &bf_head); |
1611 | bf->bf_nframes = 1; | ||
1612 | |||
1613 | ath_buf_set_rate(sc, bf); | ||
1614 | ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); | ||
1615 | } | 1631 | } |
1616 | 1632 | ||
1633 | tx_done: | ||
1617 | spin_unlock_bh(&txctl->txq->axq_lock); | 1634 | spin_unlock_bh(&txctl->txq->axq_lock); |
1618 | } | 1635 | } |
1619 | 1636 | ||