Commit 13fb6c2c authored by David S. Miller's avatar David S. Miller

Merge tag 'mac80211-for-davem-2017-06-02' of...

Merge tag 'mac80211-for-davem-2017-06-02' of git://git.kernel.org/pub/scm/linux/kernel/git/jberg/mac80211

Johannes Berg says:

====================
Just two fixes:
 * fix the per-CPU drop counters to not be added to the
   rx_packets counter, but really the drop counter
 * fix TX aggregation start/stop callback races by setting
   bits instead of allocating and queueing an skb
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ac2629a4 e165bc02
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net> * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation * Copyright 2007-2010, Intel Corporation
* Copyright(c) 2015 Intel Deutschland GmbH * Copyright(c) 2015-2017 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
...@@ -741,46 +741,43 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local, ...@@ -741,46 +741,43 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
ieee80211_agg_start_txq(sta, tid, true); ieee80211_agg_start_txq(sta, tid, true);
} }
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid) void ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid,
struct tid_ampdu_tx *tid_tx)
{ {
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
struct tid_ampdu_tx *tid_tx;
trace_api_start_tx_ba_cb(sdata, ra, tid); if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state)))
return;
if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
ieee80211_agg_tx_operational(local, sta, tid);
}
static struct tid_ampdu_tx *
ieee80211_lookup_tid_tx(struct ieee80211_sub_if_data *sdata,
const u8 *ra, u16 tid, struct sta_info **sta)
{
struct tid_ampdu_tx *tid_tx;
if (tid >= IEEE80211_NUM_TIDS) { if (tid >= IEEE80211_NUM_TIDS) {
ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n", ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
tid, IEEE80211_NUM_TIDS); tid, IEEE80211_NUM_TIDS);
return; return NULL;
} }
mutex_lock(&local->sta_mtx); *sta = sta_info_get_bss(sdata, ra);
sta = sta_info_get_bss(sdata, ra); if (!*sta) {
if (!sta) {
mutex_unlock(&local->sta_mtx);
ht_dbg(sdata, "Could not find station: %pM\n", ra); ht_dbg(sdata, "Could not find station: %pM\n", ra);
return; return NULL;
} }
mutex_lock(&sta->ampdu_mlme.mtx); tid_tx = rcu_dereference((*sta)->ampdu_mlme.tid_tx[tid]);
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (WARN_ON(!tid_tx)) { if (WARN_ON(!tid_tx))
ht_dbg(sdata, "addBA was not requested!\n"); ht_dbg(sdata, "addBA was not requested!\n");
goto unlock;
}
if (WARN_ON(test_and_set_bit(HT_AGG_STATE_DRV_READY, &tid_tx->state))) return tid_tx;
goto unlock;
if (test_bit(HT_AGG_STATE_RESPONSE_RECEIVED, &tid_tx->state))
ieee80211_agg_tx_operational(local, sta, tid);
unlock:
mutex_unlock(&sta->ampdu_mlme.mtx);
mutex_unlock(&local->sta_mtx);
} }
void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
...@@ -788,19 +785,20 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, ...@@ -788,19 +785,20 @@ void ieee80211_start_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
{ {
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_ra_tid *ra_tid; struct sta_info *sta;
struct sk_buff *skb = dev_alloc_skb(0); struct tid_ampdu_tx *tid_tx;
if (unlikely(!skb)) trace_api_start_tx_ba_cb(sdata, ra, tid);
return;
ra_tid = (struct ieee80211_ra_tid *) &skb->cb; rcu_read_lock();
memcpy(&ra_tid->ra, ra, ETH_ALEN); tid_tx = ieee80211_lookup_tid_tx(sdata, ra, tid, &sta);
ra_tid->tid = tid; if (!tid_tx)
goto out;
skb->pkt_type = IEEE80211_SDATA_QUEUE_AGG_START; set_bit(HT_AGG_STATE_START_CB, &tid_tx->state);
skb_queue_tail(&sdata->skb_queue, skb); ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
ieee80211_queue_work(&local->hw, &sdata->work); out:
rcu_read_unlock();
} }
EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe); EXPORT_SYMBOL(ieee80211_start_tx_ba_cb_irqsafe);
...@@ -860,37 +858,18 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid) ...@@ -860,37 +858,18 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
} }
EXPORT_SYMBOL(ieee80211_stop_tx_ba_session); EXPORT_SYMBOL(ieee80211_stop_tx_ba_session);
void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) void ieee80211_stop_tx_ba_cb(struct sta_info *sta, int tid,
struct tid_ampdu_tx *tid_tx)
{ {
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sta_info *sta;
struct tid_ampdu_tx *tid_tx;
bool send_delba = false; bool send_delba = false;
trace_api_stop_tx_ba_cb(sdata, ra, tid); ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n",
sta->sta.addr, tid);
if (tid >= IEEE80211_NUM_TIDS) {
ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
tid, IEEE80211_NUM_TIDS);
return;
}
ht_dbg(sdata, "Stopping Tx BA session for %pM tid %d\n", ra, tid);
mutex_lock(&local->sta_mtx);
sta = sta_info_get_bss(sdata, ra);
if (!sta) {
ht_dbg(sdata, "Could not find station: %pM\n", ra);
goto unlock;
}
mutex_lock(&sta->ampdu_mlme.mtx);
spin_lock_bh(&sta->lock); spin_lock_bh(&sta->lock);
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (!tid_tx || !test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) { if (!test_bit(HT_AGG_STATE_STOPPING, &tid_tx->state)) {
ht_dbg(sdata, ht_dbg(sdata,
"unexpected callback to A-MPDU stop for %pM tid %d\n", "unexpected callback to A-MPDU stop for %pM tid %d\n",
sta->sta.addr, tid); sta->sta.addr, tid);
...@@ -906,12 +885,8 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid) ...@@ -906,12 +885,8 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
spin_unlock_bh(&sta->lock); spin_unlock_bh(&sta->lock);
if (send_delba) if (send_delba)
ieee80211_send_delba(sdata, ra, tid, ieee80211_send_delba(sdata, sta->sta.addr, tid,
WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
mutex_unlock(&sta->ampdu_mlme.mtx);
unlock:
mutex_unlock(&local->sta_mtx);
} }
void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
...@@ -919,19 +894,20 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif, ...@@ -919,19 +894,20 @@ void ieee80211_stop_tx_ba_cb_irqsafe(struct ieee80211_vif *vif,
{ {
struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ieee80211_ra_tid *ra_tid; struct sta_info *sta;
struct sk_buff *skb = dev_alloc_skb(0); struct tid_ampdu_tx *tid_tx;
if (unlikely(!skb)) trace_api_stop_tx_ba_cb(sdata, ra, tid);
return;
ra_tid = (struct ieee80211_ra_tid *) &skb->cb; rcu_read_lock();
memcpy(&ra_tid->ra, ra, ETH_ALEN); tid_tx = ieee80211_lookup_tid_tx(sdata, ra, tid, &sta);
ra_tid->tid = tid; if (!tid_tx)
goto out;
skb->pkt_type = IEEE80211_SDATA_QUEUE_AGG_STOP; set_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state);
skb_queue_tail(&sdata->skb_queue, skb); ieee80211_queue_work(&local->hw, &sta->ampdu_mlme.work);
ieee80211_queue_work(&local->hw, &sdata->work); out:
rcu_read_unlock();
} }
EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe); EXPORT_SYMBOL(ieee80211_stop_tx_ba_cb_irqsafe);
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
* Copyright 2006-2007 Jiri Benc <jbenc@suse.cz> * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
* Copyright 2007, Michael Wu <flamingice@sourmilk.net> * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
* Copyright 2007-2010, Intel Corporation * Copyright 2007-2010, Intel Corporation
* Copyright 2017 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
...@@ -289,8 +290,6 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, ...@@ -289,8 +290,6 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
{ {
int i; int i;
cancel_work_sync(&sta->ampdu_mlme.work);
for (i = 0; i < IEEE80211_NUM_TIDS; i++) { for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
__ieee80211_stop_tx_ba_session(sta, i, reason); __ieee80211_stop_tx_ba_session(sta, i, reason);
__ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT, __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
...@@ -298,6 +297,9 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, ...@@ -298,6 +297,9 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta,
reason != AGG_STOP_DESTROY_STA && reason != AGG_STOP_DESTROY_STA &&
reason != AGG_STOP_PEER_REQUEST); reason != AGG_STOP_PEER_REQUEST);
} }
/* stopping might queue the work again - so cancel only afterwards */
cancel_work_sync(&sta->ampdu_mlme.work);
} }
void ieee80211_ba_session_work(struct work_struct *work) void ieee80211_ba_session_work(struct work_struct *work)
...@@ -352,10 +354,16 @@ void ieee80211_ba_session_work(struct work_struct *work) ...@@ -352,10 +354,16 @@ void ieee80211_ba_session_work(struct work_struct *work)
spin_unlock_bh(&sta->lock); spin_unlock_bh(&sta->lock);
tid_tx = rcu_dereference_protected_tid_tx(sta, tid); tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
if (tid_tx && test_and_clear_bit(HT_AGG_STATE_WANT_STOP, if (!tid_tx)
&tid_tx->state)) continue;
if (test_and_clear_bit(HT_AGG_STATE_START_CB, &tid_tx->state))
ieee80211_start_tx_ba_cb(sta, tid, tid_tx);
if (test_and_clear_bit(HT_AGG_STATE_WANT_STOP, &tid_tx->state))
___ieee80211_stop_tx_ba_session(sta, tid, ___ieee80211_stop_tx_ba_session(sta, tid,
AGG_STOP_LOCAL_REQUEST); AGG_STOP_LOCAL_REQUEST);
if (test_and_clear_bit(HT_AGG_STATE_STOP_CB, &tid_tx->state))
ieee80211_stop_tx_ba_cb(sta, tid, tid_tx);
} }
mutex_unlock(&sta->ampdu_mlme.mtx); mutex_unlock(&sta->ampdu_mlme.mtx);
} }
......
...@@ -1036,8 +1036,6 @@ struct ieee80211_rx_agg { ...@@ -1036,8 +1036,6 @@ struct ieee80211_rx_agg {
enum sdata_queue_type { enum sdata_queue_type {
IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0, IEEE80211_SDATA_QUEUE_TYPE_FRAME = 0,
IEEE80211_SDATA_QUEUE_AGG_START = 1,
IEEE80211_SDATA_QUEUE_AGG_STOP = 2,
IEEE80211_SDATA_QUEUE_RX_AGG_START = 3, IEEE80211_SDATA_QUEUE_RX_AGG_START = 3,
IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4, IEEE80211_SDATA_QUEUE_RX_AGG_STOP = 4,
}; };
...@@ -1427,12 +1425,6 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata) ...@@ -1427,12 +1425,6 @@ ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
return local->hw.wiphy->bands[band]; return local->hw.wiphy->bands[band];
} }
/* this struct represents 802.11n's RA/TID combination */
struct ieee80211_ra_tid {
u8 ra[ETH_ALEN];
u16 tid;
};
/* this struct holds the value parsing from channel switch IE */ /* this struct holds the value parsing from channel switch IE */
struct ieee80211_csa_ie { struct ieee80211_csa_ie {
struct cfg80211_chan_def chandef; struct cfg80211_chan_def chandef;
...@@ -1794,8 +1786,10 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, ...@@ -1794,8 +1786,10 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_agg_stop_reason reason); enum ieee80211_agg_stop_reason reason);
int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid, int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
enum ieee80211_agg_stop_reason reason); enum ieee80211_agg_stop_reason reason);
void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid); void ieee80211_start_tx_ba_cb(struct sta_info *sta, int tid,
void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid); struct tid_ampdu_tx *tid_tx);
void ieee80211_stop_tx_ba_cb(struct sta_info *sta, int tid,
struct tid_ampdu_tx *tid_tx);
void ieee80211_ba_session_work(struct work_struct *work); void ieee80211_ba_session_work(struct work_struct *work);
void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid); void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid);
void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid); void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid);
......
...@@ -1237,7 +1237,6 @@ static void ieee80211_iface_work(struct work_struct *work) ...@@ -1237,7 +1237,6 @@ static void ieee80211_iface_work(struct work_struct *work)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct sk_buff *skb; struct sk_buff *skb;
struct sta_info *sta; struct sta_info *sta;
struct ieee80211_ra_tid *ra_tid;
struct ieee80211_rx_agg *rx_agg; struct ieee80211_rx_agg *rx_agg;
if (!ieee80211_sdata_running(sdata)) if (!ieee80211_sdata_running(sdata))
...@@ -1253,15 +1252,7 @@ static void ieee80211_iface_work(struct work_struct *work) ...@@ -1253,15 +1252,7 @@ static void ieee80211_iface_work(struct work_struct *work)
while ((skb = skb_dequeue(&sdata->skb_queue))) { while ((skb = skb_dequeue(&sdata->skb_queue))) {
struct ieee80211_mgmt *mgmt = (void *)skb->data; struct ieee80211_mgmt *mgmt = (void *)skb->data;
if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_START) { if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_START) {
ra_tid = (void *)&skb->cb;
ieee80211_start_tx_ba_cb(&sdata->vif, ra_tid->ra,
ra_tid->tid);
} else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_AGG_STOP) {
ra_tid = (void *)&skb->cb;
ieee80211_stop_tx_ba_cb(&sdata->vif, ra_tid->ra,
ra_tid->tid);
} else if (skb->pkt_type == IEEE80211_SDATA_QUEUE_RX_AGG_START) {
rx_agg = (void *)&skb->cb; rx_agg = (void *)&skb->cb;
mutex_lock(&local->sta_mtx); mutex_lock(&local->sta_mtx);
sta = sta_info_get_bss(sdata, rx_agg->addr); sta = sta_info_get_bss(sdata, rx_agg->addr);
......
...@@ -2155,7 +2155,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) ...@@ -2155,7 +2155,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
struct ieee80211_sta_rx_stats *cpurxs; struct ieee80211_sta_rx_stats *cpurxs;
cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu); cpurxs = per_cpu_ptr(sta->pcpu_rx_stats, cpu);
sinfo->rx_packets += cpurxs->dropped; sinfo->rx_dropped_misc += cpurxs->dropped;
} }
} }
......
...@@ -116,6 +116,8 @@ enum ieee80211_sta_info_flags { ...@@ -116,6 +116,8 @@ enum ieee80211_sta_info_flags {
#define HT_AGG_STATE_STOPPING 3 #define HT_AGG_STATE_STOPPING 3
#define HT_AGG_STATE_WANT_START 4 #define HT_AGG_STATE_WANT_START 4
#define HT_AGG_STATE_WANT_STOP 5 #define HT_AGG_STATE_WANT_STOP 5
#define HT_AGG_STATE_START_CB 6
#define HT_AGG_STATE_STOP_CB 7
enum ieee80211_agg_stop_reason { enum ieee80211_agg_stop_reason {
AGG_STOP_DECLINED, AGG_STOP_DECLINED,
......
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