2011-08-10 19:45:52

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 1/2] mac80211: make ieee80211_send_bar available for drivers

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



2011-08-10 21:17:58

by Felix Fietkau

[permalink] [raw]
Subject: Re: [PATCH 1/2] mac80211: make ieee80211_send_bar available for drivers

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


2011-08-10 20:02:45

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/2] mac80211: make ieee80211_send_bar available for drivers

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


2011-08-10 20:28:56

by Johannes Berg

[permalink] [raw]
Subject: Re: [PATCH 1/2] mac80211: make ieee80211_send_bar available for drivers

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


2011-08-10 19:46:02

by Felix Fietkau

[permalink] [raw]
Subject: [PATCH 2/2] ath9k: use ieee80211_send_bar to send BlockAckReq frames

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