Commit 412a6d80 authored by Sara Sharon's avatar Sara Sharon Committed by Johannes Berg

mac80211: support hw managing reorder logic

Enable driver to manage the reordering logic itself.
This is needed for example for the iwlwifi driver that
will support hardware assisted reordering.
Signed-off-by: default avatarSara Sharon <sara.sharon@intel.com>
Signed-off-by: default avatarEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 50ea05ef
...@@ -1929,6 +1929,11 @@ struct ieee80211_txq { ...@@ -1929,6 +1929,11 @@ struct ieee80211_txq {
* by just its MAC address; this prevents, for example, the same station * by just its MAC address; this prevents, for example, the same station
* from connecting to two virtual AP interfaces at the same time. * from connecting to two virtual AP interfaces at the same time.
* *
* @IEEE80211_HW_SUPPORTS_REORDERING_BUFFER: Hardware (or driver) manages the
* reordering buffer internally, guaranteeing mac80211 receives frames in
* order and does not need to manage its own reorder buffer or BA session
* timeout.
*
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
*/ */
enum ieee80211_hw_flags { enum ieee80211_hw_flags {
...@@ -1965,6 +1970,7 @@ enum ieee80211_hw_flags { ...@@ -1965,6 +1970,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU, IEEE80211_HW_SUPPORTS_AMSDU_IN_AMPDU,
IEEE80211_HW_BEACON_TX_STATUS, IEEE80211_HW_BEACON_TX_STATUS,
IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR, IEEE80211_HW_NEEDS_UNIQUE_STA_ADDR,
IEEE80211_HW_SUPPORTS_REORDERING_BUFFER,
/* keep last, obviously */ /* keep last, obviously */
NUM_IEEE80211_HW_FLAGS NUM_IEEE80211_HW_FLAGS
......
...@@ -76,10 +76,11 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, ...@@ -76,10 +76,11 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid], tid_rx = rcu_dereference_protected(sta->ampdu_mlme.tid_rx[tid],
lockdep_is_held(&sta->ampdu_mlme.mtx)); lockdep_is_held(&sta->ampdu_mlme.mtx));
if (!tid_rx) if (!test_bit(tid, sta->ampdu_mlme.agg_session_valid))
return; return;
RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL); RCU_INIT_POINTER(sta->ampdu_mlme.tid_rx[tid], NULL);
__clear_bit(tid, sta->ampdu_mlme.agg_session_valid);
ht_dbg(sta->sdata, ht_dbg(sta->sdata,
"Rx BA session stop requested for %pM tid %u %s reason: %d\n", "Rx BA session stop requested for %pM tid %u %s reason: %d\n",
...@@ -97,6 +98,13 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid, ...@@ -97,6 +98,13 @@ void ___ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
ieee80211_send_delba(sta->sdata, sta->sta.addr, ieee80211_send_delba(sta->sdata, sta->sta.addr,
tid, WLAN_BACK_RECIPIENT, reason); tid, WLAN_BACK_RECIPIENT, reason);
/*
* return here in case tid_rx is not assigned - which will happen if
* IEEE80211_HW_SUPPORTS_REORDERING_BUFFER is set.
*/
if (!tid_rx)
return;
del_timer_sync(&tid_rx->session_timer); del_timer_sync(&tid_rx->session_timer);
/* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */ /* make sure ieee80211_sta_reorder_release() doesn't re-arm the timer */
...@@ -297,7 +305,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -297,7 +305,7 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
/* examine state machine */ /* examine state machine */
mutex_lock(&sta->ampdu_mlme.mtx); mutex_lock(&sta->ampdu_mlme.mtx);
if (sta->ampdu_mlme.tid_rx[tid]) { if (test_bit(tid, sta->ampdu_mlme.agg_session_valid)) {
ht_dbg_ratelimited(sta->sdata, ht_dbg_ratelimited(sta->sdata,
"unexpected AddBA Req from %pM on tid %u\n", "unexpected AddBA Req from %pM on tid %u\n",
sta->sta.addr, tid); sta->sta.addr, tid);
...@@ -308,6 +316,16 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -308,6 +316,16 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
false); false);
} }
if (ieee80211_hw_check(&local->hw, SUPPORTS_REORDERING_BUFFER)) {
ret = drv_ampdu_action(local, sta->sdata, &params);
ht_dbg(sta->sdata,
"Rx A-MPDU request on %pM tid %d result %d\n",
sta->sta.addr, tid, ret);
if (!ret)
status = WLAN_STATUS_SUCCESS;
goto end;
}
/* prepare A-MPDU MLME for Rx aggregation */ /* prepare A-MPDU MLME for Rx aggregation */
tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL); tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
if (!tid_agg_rx) if (!tid_agg_rx)
...@@ -369,6 +387,8 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta, ...@@ -369,6 +387,8 @@ void __ieee80211_start_rx_ba_session(struct sta_info *sta,
} }
end: end:
if (status == WLAN_STATUS_SUCCESS)
__set_bit(tid, sta->ampdu_mlme.agg_session_valid);
mutex_unlock(&sta->ampdu_mlme.mtx); mutex_unlock(&sta->ampdu_mlme.mtx);
end_no_lock: end_no_lock:
......
...@@ -126,6 +126,7 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = { ...@@ -126,6 +126,7 @@ static const char *hw_flag_names[NUM_IEEE80211_HW_FLAGS + 1] = {
FLAG(SUPPORTS_AMSDU_IN_AMPDU), FLAG(SUPPORTS_AMSDU_IN_AMPDU),
FLAG(BEACON_TX_STATUS), FLAG(BEACON_TX_STATUS),
FLAG(NEEDS_UNIQUE_STA_ADDR), FLAG(NEEDS_UNIQUE_STA_ADDR),
FLAG(SUPPORTS_REORDERING_BUFFER),
/* keep last for the build bug below */ /* keep last for the build bug below */
(void *)0x1 (void *)0x1
......
/* /*
* Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2002-2005, Devicescape Software, Inc.
* Copyright 2013-2014 Intel Mobile Communications GmbH * Copyright 2013-2014 Intel Mobile Communications GmbH
* Copyright(c) 2015 Intel Deutschland GmbH
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
...@@ -212,20 +213,21 @@ struct tid_ampdu_rx { ...@@ -212,20 +213,21 @@ struct tid_ampdu_rx {
/** /**
* struct sta_ampdu_mlme - STA aggregation information. * struct sta_ampdu_mlme - STA aggregation information.
* *
* @mtx: mutex to protect all TX data (except non-NULL assignments
* to tid_tx[idx], which are protected by the sta spinlock)
* tid_start_tx is also protected by sta->lock.
* @tid_rx: aggregation info for Rx per TID -- RCU protected * @tid_rx: aggregation info for Rx per TID -- RCU protected
* @tid_tx: aggregation info for Tx per TID
* @tid_start_tx: sessions where start was requested
* @addba_req_num: number of times addBA request has been sent.
* @last_addba_req_time: timestamp of the last addBA request.
* @dialog_token_allocator: dialog token enumerator for each new session;
* @work: work struct for starting/stopping aggregation
* @tid_rx_timer_expired: bitmap indicating on which TIDs the * @tid_rx_timer_expired: bitmap indicating on which TIDs the
* RX timer expired until the work for it runs * RX timer expired until the work for it runs
* @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the * @tid_rx_stop_requested: bitmap indicating which BA sessions per TID the
* driver requested to close until the work for it runs * driver requested to close until the work for it runs
* @mtx: mutex to protect all TX data (except non-NULL assignments * @agg_session_valid: bitmap indicating which TID has a rx BA session open on
* to tid_tx[idx], which are protected by the sta spinlock) * @work: work struct for starting/stopping aggregation
* tid_start_tx is also protected by sta->lock. * @tid_tx: aggregation info for Tx per TID
* @tid_start_tx: sessions where start was requested
* @last_addba_req_time: timestamp of the last addBA request.
* @addba_req_num: number of times addBA request has been sent.
* @dialog_token_allocator: dialog token enumerator for each new session;
*/ */
struct sta_ampdu_mlme { struct sta_ampdu_mlme {
struct mutex mtx; struct mutex mtx;
...@@ -233,6 +235,7 @@ struct sta_ampdu_mlme { ...@@ -233,6 +235,7 @@ struct sta_ampdu_mlme {
struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS]; struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS];
unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)]; unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
unsigned long agg_session_valid[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
/* tx */ /* tx */
struct work_struct work; struct work_struct work;
struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS]; struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];
......
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