Commit 17c18bf8 authored by Johannes Berg's avatar Johannes Berg

mac80211: add TX fastpath

In order to speed up mac80211's TX path, add the "fast-xmit" cache
that will cache the data frame 802.11 header and other data to be
able to build the frame more quickly. This cache is rebuilt when
external triggers imply changes, but a lot of the checks done per
packet today are simplified away to the check for the cache.

There's also a more detailed description in the code.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent a839e463
...@@ -1796,6 +1796,10 @@ struct ieee80211_txq { ...@@ -1796,6 +1796,10 @@ struct ieee80211_txq {
* the driver returns 1. This also forces the driver to advertise its * the driver returns 1. This also forces the driver to advertise its
* supported cipher suites. * supported cipher suites.
* *
* @IEEE80211_HW_SUPPORT_FAST_XMIT: The driver/hardware supports fast-xmit,
* this currently requires only the ability to calculate the duration
* for frames.
*
* @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface * @IEEE80211_HW_QUEUE_CONTROL: The driver wants to control per-interface
* queue mapping in order to use different queues (not just one per AC) * queue mapping in order to use different queues (not just one per AC)
* for different virtual interfaces. See the doc section on HW queue * for different virtual interfaces. See the doc section on HW queue
...@@ -1844,7 +1848,7 @@ enum ieee80211_hw_flags { ...@@ -1844,7 +1848,7 @@ enum ieee80211_hw_flags {
IEEE80211_HW_WANT_MONITOR_VIF = 1<<14, IEEE80211_HW_WANT_MONITOR_VIF = 1<<14,
IEEE80211_HW_NO_AUTO_VIF = 1<<15, IEEE80211_HW_NO_AUTO_VIF = 1<<15,
IEEE80211_HW_SW_CRYPTO_CONTROL = 1<<16, IEEE80211_HW_SW_CRYPTO_CONTROL = 1<<16,
/* free slots */ IEEE80211_HW_SUPPORT_FAST_XMIT = 1<<17,
IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18, IEEE80211_HW_REPORTS_TX_ACK_STATUS = 1<<18,
IEEE80211_HW_CONNECTION_MONITOR = 1<<19, IEEE80211_HW_CONNECTION_MONITOR = 1<<19,
IEEE80211_HW_QUEUE_CONTROL = 1<<20, IEEE80211_HW_QUEUE_CONTROL = 1<<20,
......
...@@ -137,6 +137,9 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy, ...@@ -137,6 +137,9 @@ static int ieee80211_set_noack_map(struct wiphy *wiphy,
struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
sdata->noack_map = noack_map; sdata->noack_map = noack_map;
ieee80211_check_fast_xmit_iface(sdata);
return 0; return 0;
} }
...@@ -2099,10 +2102,14 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed) ...@@ -2099,10 +2102,14 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
int err; int err;
if (changed & WIPHY_PARAM_FRAG_THRESHOLD) { if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
ieee80211_check_fast_xmit_all(local);
err = drv_set_frag_threshold(local, wiphy->frag_threshold); err = drv_set_frag_threshold(local, wiphy->frag_threshold);
if (err) if (err) {
ieee80211_check_fast_xmit_all(local);
return err; return err;
}
} }
if ((changed & WIPHY_PARAM_COVERAGE_CLASS) || if ((changed & WIPHY_PARAM_COVERAGE_CLASS) ||
......
...@@ -664,6 +664,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata, ...@@ -664,6 +664,8 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
ieee80211_bss_info_change_notify(sdata, ieee80211_bss_info_change_notify(sdata,
BSS_CHANGED_IDLE); BSS_CHANGED_IDLE);
ieee80211_check_fast_xmit_iface(sdata);
return ret; return ret;
} }
...@@ -1030,6 +1032,8 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata) ...@@ -1030,6 +1032,8 @@ ieee80211_vif_use_reserved_reassign(struct ieee80211_sub_if_data *sdata)
if (sdata->vif.type == NL80211_IFTYPE_AP) if (sdata->vif.type == NL80211_IFTYPE_AP)
__ieee80211_vif_copy_chanctx_to_vlans(sdata, false); __ieee80211_vif_copy_chanctx_to_vlans(sdata, false);
ieee80211_check_fast_xmit_iface(sdata);
if (ieee80211_chanctx_refcount(local, old_ctx) == 0) if (ieee80211_chanctx_refcount(local, old_ctx) == 0)
ieee80211_free_chanctx(local, old_ctx); ieee80211_free_chanctx(local, old_ctx);
...@@ -1376,6 +1380,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local) ...@@ -1376,6 +1380,8 @@ static int ieee80211_vif_use_reserved_switch(struct ieee80211_local *local)
__ieee80211_vif_copy_chanctx_to_vlans(sdata, __ieee80211_vif_copy_chanctx_to_vlans(sdata,
false); false);
ieee80211_check_fast_xmit_iface(sdata);
sdata->radar_required = sdata->reserved_radar_required; sdata->radar_required = sdata->reserved_radar_required;
if (sdata->vif.bss_conf.chandef.width != if (sdata->vif.bss_conf.chandef.width !=
......
...@@ -1651,6 +1651,11 @@ struct sk_buff * ...@@ -1651,6 +1651,11 @@ struct sk_buff *
ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata, ieee80211_build_data_template(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb, u32 info_flags); struct sk_buff *skb, u32 info_flags);
void ieee80211_check_fast_xmit(struct sta_info *sta);
void ieee80211_check_fast_xmit_all(struct ieee80211_local *local);
void ieee80211_check_fast_xmit_iface(struct ieee80211_sub_if_data *sdata);
void ieee80211_clear_fast_xmit(struct sta_info *sta);
/* HT */ /* HT */
void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sta_ht_cap *ht_cap); struct ieee80211_sta_ht_cap *ht_cap);
......
...@@ -229,6 +229,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata, ...@@ -229,6 +229,7 @@ static void __ieee80211_set_default_key(struct ieee80211_sub_if_data *sdata,
if (uni) { if (uni) {
rcu_assign_pointer(sdata->default_unicast_key, key); rcu_assign_pointer(sdata->default_unicast_key, key);
ieee80211_check_fast_xmit_iface(sdata);
drv_set_default_unicast_key(sdata->local, sdata, idx); drv_set_default_unicast_key(sdata->local, sdata, idx);
} }
...@@ -298,6 +299,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, ...@@ -298,6 +299,7 @@ static void ieee80211_key_replace(struct ieee80211_sub_if_data *sdata,
if (pairwise) { if (pairwise) {
rcu_assign_pointer(sta->ptk[idx], new); rcu_assign_pointer(sta->ptk[idx], new);
sta->ptk_idx = idx; sta->ptk_idx = idx;
ieee80211_check_fast_xmit(sta);
} else { } else {
rcu_assign_pointer(sta->gtk[idx], new); rcu_assign_pointer(sta->gtk[idx], new);
sta->gtk_idx = idx; sta->gtk_idx = idx;
......
...@@ -1200,6 +1200,8 @@ static void sta_ps_start(struct sta_info *sta) ...@@ -1200,6 +1200,8 @@ static void sta_ps_start(struct sta_info *sta)
ps_dbg(sdata, "STA %pM aid %d enters power save mode\n", ps_dbg(sdata, "STA %pM aid %d enters power save mode\n",
sta->sta.addr, sta->sta.aid); sta->sta.addr, sta->sta.aid);
ieee80211_clear_fast_xmit(sta);
if (!sta->sta.txq[0]) if (!sta->sta.txq[0])
return; return;
......
...@@ -1201,6 +1201,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) ...@@ -1201,6 +1201,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
ps_dbg(sdata, ps_dbg(sdata,
"STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n", "STA %pM aid %d sending %d filtered/%d PS frames since STA not sleeping anymore\n",
sta->sta.addr, sta->sta.aid, filtered, buffered); sta->sta.addr, sta->sta.aid, filtered, buffered);
ieee80211_check_fast_xmit(sta);
} }
static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata, static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
...@@ -1599,6 +1601,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, ...@@ -1599,6 +1601,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
if (block) { if (block) {
set_sta_flag(sta, WLAN_STA_PS_DRIVER); set_sta_flag(sta, WLAN_STA_PS_DRIVER);
ieee80211_clear_fast_xmit(sta);
return; return;
} }
...@@ -1616,6 +1619,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw, ...@@ -1616,6 +1619,7 @@ void ieee80211_sta_block_awake(struct ieee80211_hw *hw,
ieee80211_queue_work(hw, &sta->drv_deliver_wk); ieee80211_queue_work(hw, &sta->drv_deliver_wk);
} else { } else {
clear_sta_flag(sta, WLAN_STA_PS_DRIVER); clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
ieee80211_check_fast_xmit(sta);
} }
} }
EXPORT_SYMBOL(ieee80211_sta_block_awake); EXPORT_SYMBOL(ieee80211_sta_block_awake);
...@@ -1720,6 +1724,7 @@ int sta_info_move_state(struct sta_info *sta, ...@@ -1720,6 +1724,7 @@ int sta_info_move_state(struct sta_info *sta,
!sta->sdata->u.vlan.sta)) !sta->sdata->u.vlan.sta))
atomic_dec(&sta->sdata->bss->num_mcast_sta); atomic_dec(&sta->sdata->bss->num_mcast_sta);
clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags); clear_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_clear_fast_xmit(sta);
} }
break; break;
case IEEE80211_STA_AUTHORIZED: case IEEE80211_STA_AUTHORIZED:
...@@ -1729,6 +1734,7 @@ int sta_info_move_state(struct sta_info *sta, ...@@ -1729,6 +1734,7 @@ int sta_info_move_state(struct sta_info *sta,
!sta->sdata->u.vlan.sta)) !sta->sdata->u.vlan.sta))
atomic_inc(&sta->sdata->bss->num_mcast_sta); atomic_inc(&sta->sdata->bss->num_mcast_sta);
set_bit(WLAN_STA_AUTHORIZED, &sta->_flags); set_bit(WLAN_STA_AUTHORIZED, &sta->_flags);
ieee80211_check_fast_xmit(sta);
} }
break; break;
default: default:
......
...@@ -241,6 +241,30 @@ struct sta_ampdu_mlme { ...@@ -241,6 +241,30 @@ struct sta_ampdu_mlme {
/* Value to indicate no TID reservation */ /* Value to indicate no TID reservation */
#define IEEE80211_TID_UNRESERVED 0xff #define IEEE80211_TID_UNRESERVED 0xff
/**
* struct ieee80211_fast_tx - TX fastpath information
* @key: key to use for hw crypto
* @hdr: the 802.11 header to put with the frame
* @hdr_len: actual 802.11 header length
* @sa_offs: offset of the SA
* @da_offs: offset of the DA
* @pn_offs: offset where to put PN for crypto (or 0 if not needed)
* @band: band this will be transmitted on, for tx_info
* @rcu_head: RCU head to free this struct
*
* Try to keep this struct small so it fits into a single cacheline.
*/
struct ieee80211_fast_tx {
struct ieee80211_key *key;
u8 hdr[30 + 2 + IEEE80211_CCMP_HDR_LEN +
sizeof(rfc1042_header)];
u8 hdr_len;
u8 sa_offs, da_offs, pn_offs;
u8 band;
struct rcu_head rcu_head;
};
/** /**
* struct sta_info - STA information * struct sta_info - STA information
* *
...@@ -339,6 +363,7 @@ struct sta_ampdu_mlme { ...@@ -339,6 +363,7 @@ struct sta_ampdu_mlme {
* using IEEE80211_NUM_TID entry for non-QoS frames * using IEEE80211_NUM_TID entry for non-QoS frames
* @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID * @rx_msdu: MSDUs received from this station, using IEEE80211_NUM_TID
* entry for non-QoS frames * entry for non-QoS frames
* @fast_tx: TX fastpath information
*/ */
struct sta_info { struct sta_info {
/* General information, mostly static */ /* General information, mostly static */
...@@ -356,6 +381,8 @@ struct sta_info { ...@@ -356,6 +381,8 @@ struct sta_info {
spinlock_t rate_ctrl_lock; spinlock_t rate_ctrl_lock;
spinlock_t lock; spinlock_t lock;
struct ieee80211_fast_tx __rcu *fast_tx;
struct work_struct drv_deliver_wk; struct work_struct drv_deliver_wk;
u16 listen_interval; u16 listen_interval;
......
This diff is collapsed.
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