mac80211: support hardware TX fragmentation offload
The lower driver is notified when the fragmentation threshold changes and upon a reconfig of the interface. If the driver supports hardware TX fragmentation, don't fragment packets in the stack. Signed-off-by: Arik Nemtsov <arik@wizery.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
parent
ca4a083191
commit
f23a478075
|
@ -1652,6 +1652,11 @@ enum ieee80211_ampdu_mlme_action {
|
||||||
* and IV16) for the given key from hardware.
|
* and IV16) for the given key from hardware.
|
||||||
* The callback must be atomic.
|
* The callback must be atomic.
|
||||||
*
|
*
|
||||||
|
* @set_frag_threshold: Configuration of fragmentation threshold. Assign this
|
||||||
|
* if the device does fragmentation by itself; if this callback is
|
||||||
|
* implemented then the stack will not do fragmentation.
|
||||||
|
* The callback can sleep.
|
||||||
|
*
|
||||||
* @set_rts_threshold: Configuration of RTS threshold (if device needs it)
|
* @set_rts_threshold: Configuration of RTS threshold (if device needs it)
|
||||||
* The callback can sleep.
|
* The callback can sleep.
|
||||||
*
|
*
|
||||||
|
@ -1765,6 +1770,7 @@ struct ieee80211_ops {
|
||||||
struct ieee80211_low_level_stats *stats);
|
struct ieee80211_low_level_stats *stats);
|
||||||
void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
|
void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
|
||||||
u32 *iv32, u16 *iv16);
|
u32 *iv32, u16 *iv16);
|
||||||
|
int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value);
|
||||||
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
|
int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value);
|
||||||
int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
int (*sta_add)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
|
||||||
struct ieee80211_sta *sta);
|
struct ieee80211_sta *sta);
|
||||||
|
|
|
@ -1299,6 +1299,13 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
|
||||||
struct ieee80211_local *local = wiphy_priv(wiphy);
|
struct ieee80211_local *local = wiphy_priv(wiphy);
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
|
||||||
|
err = drv_set_frag_threshold(local, wiphy->frag_threshold);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
|
if (changed & WIPHY_PARAM_COVERAGE_CLASS) {
|
||||||
err = drv_set_coverage_class(local, wiphy->coverage_class);
|
err = drv_set_coverage_class(local, wiphy->coverage_class);
|
||||||
|
|
||||||
|
|
|
@ -233,6 +233,20 @@ static inline void drv_get_tkip_seq(struct ieee80211_local *local,
|
||||||
trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
|
trace_drv_get_tkip_seq(local, hw_key_idx, iv32, iv16);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline int drv_set_frag_threshold(struct ieee80211_local *local,
|
||||||
|
u32 value)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
might_sleep();
|
||||||
|
|
||||||
|
trace_drv_set_frag_threshold(local, value);
|
||||||
|
if (local->ops->set_frag_threshold)
|
||||||
|
ret = local->ops->set_frag_threshold(&local->hw, value);
|
||||||
|
trace_drv_return_int(local, ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static inline int drv_set_rts_threshold(struct ieee80211_local *local,
|
static inline int drv_set_rts_threshold(struct ieee80211_local *local,
|
||||||
u32 value)
|
u32 value)
|
||||||
{
|
{
|
||||||
|
|
|
@ -531,6 +531,27 @@ TRACE_EVENT(drv_get_tkip_seq,
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
TRACE_EVENT(drv_set_frag_threshold,
|
||||||
|
TP_PROTO(struct ieee80211_local *local, u32 value),
|
||||||
|
|
||||||
|
TP_ARGS(local, value),
|
||||||
|
|
||||||
|
TP_STRUCT__entry(
|
||||||
|
LOCAL_ENTRY
|
||||||
|
__field(u32, value)
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_fast_assign(
|
||||||
|
LOCAL_ASSIGN;
|
||||||
|
__entry->value = value;
|
||||||
|
),
|
||||||
|
|
||||||
|
TP_printk(
|
||||||
|
LOCAL_PR_FMT " value:%d",
|
||||||
|
LOCAL_PR_ARG, __entry->value
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
TRACE_EVENT(drv_set_rts_threshold,
|
TRACE_EVENT(drv_set_rts_threshold,
|
||||||
TP_PROTO(struct ieee80211_local *local, u32 value),
|
TP_PROTO(struct ieee80211_local *local, u32 value),
|
||||||
|
|
||||||
|
|
|
@ -1033,6 +1033,7 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
|
||||||
struct ieee80211_radiotap_header *rthdr =
|
struct ieee80211_radiotap_header *rthdr =
|
||||||
(struct ieee80211_radiotap_header *) skb->data;
|
(struct ieee80211_radiotap_header *) skb->data;
|
||||||
struct ieee80211_supported_band *sband;
|
struct ieee80211_supported_band *sband;
|
||||||
|
bool hw_frag;
|
||||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||||
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
|
int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len,
|
||||||
NULL);
|
NULL);
|
||||||
|
@ -1042,6 +1043,9 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
|
||||||
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
info->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||||
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
|
tx->flags &= ~IEEE80211_TX_FRAGMENTED;
|
||||||
|
|
||||||
|
/* packet is fragmented in HW if we have a non-NULL driver callback */
|
||||||
|
hw_frag = (tx->local->ops->set_frag_threshold != NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* for every radiotap entry that is present
|
* for every radiotap entry that is present
|
||||||
* (ieee80211_radiotap_iterator_next returns -ENOENT when no more
|
* (ieee80211_radiotap_iterator_next returns -ENOENT when no more
|
||||||
|
@ -1078,7 +1082,8 @@ static bool __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx,
|
||||||
}
|
}
|
||||||
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
|
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_WEP)
|
||||||
info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
info->flags &= ~IEEE80211_TX_INTFL_DONT_ENCRYPT;
|
||||||
if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG)
|
if ((*iterator.this_arg & IEEE80211_RADIOTAP_F_FRAG) &&
|
||||||
|
!hw_frag)
|
||||||
tx->flags |= IEEE80211_TX_FRAGMENTED;
|
tx->flags |= IEEE80211_TX_FRAGMENTED;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -1181,8 +1186,10 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
|
||||||
/*
|
/*
|
||||||
* Set this flag (used below to indicate "automatic fragmentation"),
|
* Set this flag (used below to indicate "automatic fragmentation"),
|
||||||
* it will be cleared/left by radiotap as desired.
|
* it will be cleared/left by radiotap as desired.
|
||||||
|
* Only valid when fragmentation is done by the stack.
|
||||||
*/
|
*/
|
||||||
tx->flags |= IEEE80211_TX_FRAGMENTED;
|
if (!local->ops->set_frag_threshold)
|
||||||
|
tx->flags |= IEEE80211_TX_FRAGMENTED;
|
||||||
|
|
||||||
/* process and remove the injection radiotap header */
|
/* process and remove the injection radiotap header */
|
||||||
if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
|
if (unlikely(info->flags & IEEE80211_TX_INTFL_HAS_RADIOTAP)) {
|
||||||
|
|
|
@ -1152,6 +1152,9 @@ int ieee80211_reconfig(struct ieee80211_local *local)
|
||||||
}
|
}
|
||||||
mutex_unlock(&local->sta_mtx);
|
mutex_unlock(&local->sta_mtx);
|
||||||
|
|
||||||
|
/* setup fragmentation threshold */
|
||||||
|
drv_set_frag_threshold(local, hw->wiphy->frag_threshold);
|
||||||
|
|
||||||
/* setup RTS threshold */
|
/* setup RTS threshold */
|
||||||
drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
|
drv_set_rts_threshold(local, hw->wiphy->rts_threshold);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue