To properly maintain the peer's block ack window, the driver needs to be
able to control the new starting sequence number that is sent along with
the BlockAckReq frame.
Signed-off-by: Felix Fietkau <[email protected]>
---
include/net/mac80211.h | 13 +++++++++++++
net/mac80211/agg-tx.c | 4 +++-
net/mac80211/ieee80211_i.h | 1 -
net/mac80211/status.c | 2 +-
4 files changed, 17 insertions(+), 3 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 2f01d84..03e5ad8 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3218,6 +3218,19 @@ void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
const u8 *addr);
+/**
+ * ieee80211_send_bar - send a BlockAckReq frame
+ *
+ * can be used to flush pending frames from the peer's aggregation reorder
+ * buffer.
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @ra: the peer's destination address
+ * @tid: the TID of the aggregation session
+ * @ssn: the new starting sequence number for the receiver
+ */
+void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
+
/* Rate control API */
/**
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index b7075f3..62d61fb 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -106,8 +106,9 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
ieee80211_tx_skb(sdata, skb);
}
-void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn)
+void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn)
{
+ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local;
struct sk_buff *skb;
struct ieee80211_bar *bar;
@@ -135,6 +136,7 @@ void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u1
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
ieee80211_tx_skb(sdata, skb);
}
+EXPORT_SYMBOL(ieee80211_send_bar);
void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
struct tid_ampdu_tx *tid_tx)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 286ac5d..9ea38b5 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1248,7 +1248,6 @@ struct ieee80211_tx_status_rtap_hdr {
void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
struct ieee80211_ht_cap *ht_cap_ie,
struct ieee80211_sta_ht_cap *ht_cap);
-void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn);
void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
const u8 *da, u16 tid,
u16 initiator, u16 reason_code);
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index a89cca3..95e0a8b 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -239,7 +239,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
tid = qc[0] & 0xf;
ssn = ((le16_to_cpu(hdr->seq_ctrl) + 0x10)
& IEEE80211_SCTL_SEQ);
- ieee80211_send_bar(sta->sdata, hdr->addr1,
+ ieee80211_send_bar(&sta->sdata->vif, hdr->addr1,
tid, ssn);
}
--
1.7.3.2
On 2011-08-10 2:02 PM, Johannes Berg wrote:
> On Wed, 2011-08-10 at 13:45 -0600, Felix Fietkau wrote:
>> To properly maintain the peer's block ack window, the driver needs to be
>> able to control the new starting sequence number that is sent along with
>> the BlockAckReq frame.
>
> I guess with the ath9k patch I understand ... I believe iwlwifi
> processes all of the TX status and only sets the BAR flag on the last
> one?
>
>> +/**
>> + * ieee80211_send_bar - send a BlockAckReq frame
>> + *
>> + * can be used to flush pending frames from the peer's aggregation reorder
>> + * buffer.
>> + *
>> + * @vif:&struct ieee80211_vif pointer from the add_interface callback.
>> + * @ra: the peer's destination address
>> + * @tid: the TID of the aggregation session
>> + * @ssn: the new starting sequence number for the receiver
>> + */
>> +void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
>
> You might want to note the locking rules, it's a little strange here
> since it calls right back into the driver's tx(). Though of course the
> same also happens with tx_status(), it might be less expected here,
> especially if you use tx_status_irqsafe() and this doesn't yet have an
> irqsafe version.
I think it's not that important, so if you want to avoid adding a new
API, I can also make a simple ath9k patch that reduces the number of
BARs sent.
- Felix
On Wed, 2011-08-10 at 13:45 -0600, Felix Fietkau wrote:
> To properly maintain the peer's block ack window, the driver needs to be
> able to control the new starting sequence number that is sent along with
> the BlockAckReq frame.
I guess with the ath9k patch I understand ... I believe iwlwifi
processes all of the TX status and only sets the BAR flag on the last
one?
> +/**
> + * ieee80211_send_bar - send a BlockAckReq frame
> + *
> + * can be used to flush pending frames from the peer's aggregation reorder
> + * buffer.
> + *
> + * @vif: &struct ieee80211_vif pointer from the add_interface callback.
> + * @ra: the peer's destination address
> + * @tid: the TID of the aggregation session
> + * @ssn: the new starting sequence number for the receiver
> + */
> +void ieee80211_send_bar(struct ieee80211_vif *vif, u8 *ra, u16 tid, u16 ssn);
You might want to note the locking rules, it's a little strange here
since it calls right back into the driver's tx(). Though of course the
same also happens with tx_status(), it might be less expected here,
especially if you use tx_status_irqsafe() and this doesn't yet have an
irqsafe version.
johannes
On Wed, 2011-08-10 at 13:45 -0600, Felix Fietkau wrote:
> + * @vif: &struct ieee80211_vif pointer from the add_interface callback.
> + * @ra: the peer's destination address
> + * @tid: the TID of the aggregation session
> + * @ssn: the new starting sequence number for the receiver
might want to say that ssn is with fragno in it :)
johannes
Instead of letting mac80211 send one BAR per expired subframe, process
all tx status for an aggregate and if a frame was dropped, send only
one BAR afterwards.
Signed-off-by: Felix Fietkau <[email protected]>
---
drivers/net/wireless/ath/ath9k/ath9k.h | 2 +-
drivers/net/wireless/ath/ath9k/main.c | 1 +
drivers/net/wireless/ath/ath9k/xmit.c | 31 ++++++++++++++-----------------
3 files changed, 16 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index c03949e..9cbb7ecd 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -251,6 +251,7 @@ struct ath_atx_tid {
};
struct ath_node {
+ struct ieee80211_vif *vif;
#ifdef CONFIG_ATH9K_DEBUGFS
struct list_head list; /* for sc->nodes */
struct ieee80211_sta *sta; /* station struct we're part of */
@@ -277,7 +278,6 @@ struct ath_tx_control {
#define ATH_TX_ERROR 0x01
#define ATH_TX_XRETRY 0x02
-#define ATH_TX_BAR 0x04
/**
* @txq_map: Index is mac80211 queue number. This is
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 1e7fe8c..313a768 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -1801,6 +1801,7 @@ static int ath9k_sta_add(struct ieee80211_hw *hw,
struct ieee80211_key_conf ps_key = { };
ath_node_attach(sc, sta);
+ an->vif = vif;
if (vif->type != NL80211_IFTYPE_AP &&
vif->type != NL80211_IFTYPE_AP_VLAN)
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index e815e82..46ac061 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -52,7 +52,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
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);
+ struct ath_tx_status *ts, int txok);
static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
struct list_head *head, bool internal);
static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
@@ -167,7 +167,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
fi = get_frame_info(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, 1);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
} else {
ath_tx_send_normal(sc, txq, NULL, &bf_head);
}
@@ -239,7 +239,7 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_update_baw(sc, tid, fi->seqno);
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);
spin_lock(&txq->axq_lock);
}
@@ -382,8 +382,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
list_move_tail(&bf->list, &bf_head);
ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
- ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
- 0, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, ts, 0);
bf = bf_next;
}
@@ -427,7 +426,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_count_frames(sc, bf, ts, txok, &nframes, &nbad);
while (bf) {
- txfail = txpending = sendbar = 0;
+ txfail = txpending = 0;
bf_next = bf->bf_next;
skb = bf->bf_mpdu;
@@ -490,7 +489,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
}
ath_tx_complete_buf(sc, bf, txq, &bf_head, ts,
- !txfail, sendbar);
+ !txfail);
} else {
/* retry the un-acked ones */
ath9k_hw_set_clrdmask(sc->sc_ah, bf->bf_desc, false);
@@ -515,7 +514,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
nbad, 0, false);
ath_tx_complete_buf(sc, bf, txq,
&bf_head,
- ts, 0, 0);
+ ts, 0);
break;
}
@@ -564,6 +563,9 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
}
}
+ if (sendbar || (tid->state & AGGR_CLEANUP))
+ ieee80211_send_bar(an->vif, sta->addr, tidno, tid->seq_start << 4);
+
rcu_read_unlock();
if (needreset)
@@ -900,6 +902,7 @@ void ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid)
spin_unlock_bh(&txq->axq_lock);
ath_tx_flush_tid(sc, txtid);
+ ieee80211_send_bar(an->vif, sta->addr, tid, txtid->seq_start << 4);
}
bool ath_tx_aggr_sleep(struct ath_softc *sc, struct ath_node *an)
@@ -1180,7 +1183,7 @@ static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
retry_tx);
else
- ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
+ ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0);
spin_lock_bh(&txq->axq_lock);
}
}
@@ -1885,9 +1888,6 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
- if (tx_flags & ATH_TX_BAR)
- tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
-
if (!(tx_flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) {
/* Frame was ACKed */
tx_info->flags |= IEEE80211_TX_STAT_ACK;
@@ -1932,15 +1932,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
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)
+ struct ath_tx_status *ts, int txok)
{
struct sk_buff *skb = bf->bf_mpdu;
unsigned long flags;
int tx_flags = 0;
- if (sendbar)
- tx_flags = ATH_TX_BAR;
-
if (!txok) {
tx_flags |= ATH_TX_ERROR;
@@ -2057,7 +2054,7 @@ static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
if (ts->ts_status & ATH9K_TXERR_XRETRY)
bf->bf_state.bf_type |= BUF_XRETRY;
ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
- ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
+ ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok);
} else
ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
--
1.7.3.2