Commit d421c62e authored by John W. Linville's avatar John W. Linville
parents 4885c873 e3685e03
...@@ -1692,14 +1692,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, ...@@ -1692,14 +1692,8 @@ void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue); void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue);
void ieee80211_add_pending_skb(struct ieee80211_local *local, void ieee80211_add_pending_skb(struct ieee80211_local *local,
struct sk_buff *skb); struct sk_buff *skb);
void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, void ieee80211_add_pending_skbs(struct ieee80211_local *local,
struct sk_buff_head *skbs, struct sk_buff_head *skbs);
void (*fn)(void *data), void *data);
static inline void ieee80211_add_pending_skbs(struct ieee80211_local *local,
struct sk_buff_head *skbs)
{
ieee80211_add_pending_skbs_fn(local, skbs, NULL, NULL);
}
void ieee80211_flush_queues(struct ieee80211_local *local, void ieee80211_flush_queues(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata); struct ieee80211_sub_if_data *sdata);
......
...@@ -3753,6 +3753,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata, ...@@ -3753,6 +3753,7 @@ static int ieee80211_prep_connection(struct ieee80211_sub_if_data *sdata,
chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf); chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
if (WARN_ON(!chanctx_conf)) { if (WARN_ON(!chanctx_conf)) {
rcu_read_unlock(); rcu_read_unlock();
sta_info_free(local, new_sta);
return -EINVAL; return -EINVAL;
} }
rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def); rate_flags = ieee80211_chandef_rate_flags(&chanctx_conf->def);
......
...@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *sta) ...@@ -1128,6 +1128,13 @@ static void sta_ps_end(struct sta_info *sta)
sta->sta.addr, sta->sta.aid); sta->sta.addr, sta->sta.aid);
if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) { if (test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
/*
* Clear the flag only if the other one is still set
* so that the TX path won't start TX'ing new frames
* directly ... In the case that the driver flag isn't
* set ieee80211_sta_ps_deliver_wakeup() will clear it.
*/
clear_sta_flag(sta, WLAN_STA_PS_STA);
ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n", ps_dbg(sta->sdata, "STA %pM aid %d driver-ps-blocked\n",
sta->sta.addr, sta->sta.aid); sta->sta.addr, sta->sta.aid);
return; return;
......
...@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local, ...@@ -91,7 +91,7 @@ static int sta_info_hash_del(struct ieee80211_local *local,
return -ENOENT; return -ENOENT;
} }
static void cleanup_single_sta(struct sta_info *sta) static void __cleanup_single_sta(struct sta_info *sta)
{ {
int ac, i; int ac, i;
struct tid_ampdu_tx *tid_tx; struct tid_ampdu_tx *tid_tx;
...@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct sta_info *sta) ...@@ -99,7 +99,8 @@ static void cleanup_single_sta(struct sta_info *sta)
struct ieee80211_local *local = sdata->local; struct ieee80211_local *local = sdata->local;
struct ps_data *ps; struct ps_data *ps;
if (test_sta_flag(sta, WLAN_STA_PS_STA)) { if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
if (sta->sdata->vif.type == NL80211_IFTYPE_AP || if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN) sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
ps = &sdata->bss->ps; ps = &sdata->bss->ps;
...@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct sta_info *sta) ...@@ -109,6 +110,7 @@ static void cleanup_single_sta(struct sta_info *sta)
return; return;
clear_sta_flag(sta, WLAN_STA_PS_STA); clear_sta_flag(sta, WLAN_STA_PS_STA);
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
atomic_dec(&ps->num_sta_ps); atomic_dec(&ps->num_sta_ps);
sta_info_recalc_tim(sta); sta_info_recalc_tim(sta);
...@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct sta_info *sta) ...@@ -139,7 +141,14 @@ static void cleanup_single_sta(struct sta_info *sta)
ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending); ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
kfree(tid_tx); kfree(tid_tx);
} }
}
static void cleanup_single_sta(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
__cleanup_single_sta(sta);
sta_info_free(local, sta); sta_info_free(local, sta);
} }
...@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, ...@@ -330,6 +339,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
rcu_read_unlock(); rcu_read_unlock();
spin_lock_init(&sta->lock); spin_lock_init(&sta->lock);
spin_lock_init(&sta->ps_lock);
INIT_WORK(&sta->drv_unblock_wk, sta_unblock); INIT_WORK(&sta->drv_unblock_wk, sta_unblock);
INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work);
mutex_init(&sta->ampdu_mlme.mtx); mutex_init(&sta->ampdu_mlme.mtx);
...@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) ...@@ -487,21 +497,26 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
goto out_err; goto out_err;
} }
/* notify driver */
err = sta_info_insert_drv_state(local, sdata, sta);
if (err)
goto out_err;
local->num_sta++; local->num_sta++;
local->sta_generation++; local->sta_generation++;
smp_mb(); smp_mb();
/* simplify things and don't accept BA sessions yet */
set_sta_flag(sta, WLAN_STA_BLOCK_BA);
/* make the station visible */ /* make the station visible */
sta_info_hash_add(local, sta); sta_info_hash_add(local, sta);
list_add_rcu(&sta->list, &local->sta_list); list_add_rcu(&sta->list, &local->sta_list);
/* notify driver */
err = sta_info_insert_drv_state(local, sdata, sta);
if (err)
goto out_remove;
set_sta_flag(sta, WLAN_STA_INSERTED); set_sta_flag(sta, WLAN_STA_INSERTED);
/* accept BA sessions now */
clear_sta_flag(sta, WLAN_STA_BLOCK_BA);
ieee80211_recalc_min_chandef(sdata); ieee80211_recalc_min_chandef(sdata);
ieee80211_sta_debugfs_add(sta); ieee80211_sta_debugfs_add(sta);
...@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU) ...@@ -522,6 +537,12 @@ static int sta_info_insert_finish(struct sta_info *sta) __acquires(RCU)
mesh_accept_plinks_update(sdata); mesh_accept_plinks_update(sdata);
return 0; return 0;
out_remove:
sta_info_hash_del(local, sta);
list_del_rcu(&sta->list);
local->num_sta--;
synchronize_net();
__cleanup_single_sta(sta);
out_err: out_err:
mutex_unlock(&local->sta_mtx); mutex_unlock(&local->sta_mtx);
rcu_read_lock(); rcu_read_lock();
...@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif, ...@@ -1071,10 +1092,14 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_vif *vif,
} }
EXPORT_SYMBOL(ieee80211_find_sta); EXPORT_SYMBOL(ieee80211_find_sta);
static void clear_sta_ps_flags(void *_sta) /* powersave support code */
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{ {
struct sta_info *sta = _sta;
struct ieee80211_sub_if_data *sdata = sta->sdata; struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff_head pending;
int filtered = 0, buffered = 0, ac;
unsigned long flags;
struct ps_data *ps; struct ps_data *ps;
if (sdata->vif.type == NL80211_IFTYPE_AP || if (sdata->vif.type == NL80211_IFTYPE_AP ||
...@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta) ...@@ -1085,20 +1110,6 @@ static void clear_sta_ps_flags(void *_sta)
else else
return; return;
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
if (test_and_clear_sta_flag(sta, WLAN_STA_PS_STA))
atomic_dec(&ps->num_sta_ps);
}
/* powersave support code */
void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
{
struct ieee80211_sub_if_data *sdata = sta->sdata;
struct ieee80211_local *local = sdata->local;
struct sk_buff_head pending;
int filtered = 0, buffered = 0, ac;
unsigned long flags;
clear_sta_flag(sta, WLAN_STA_SP); clear_sta_flag(sta, WLAN_STA_SP);
BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1); BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
...@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) ...@@ -1109,6 +1120,8 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
skb_queue_head_init(&pending); skb_queue_head_init(&pending);
/* sync with ieee80211_tx_h_unicast_ps_buf */
spin_lock(&sta->ps_lock);
/* Send all buffered frames to the station */ /* Send all buffered frames to the station */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
int count = skb_queue_len(&pending), tmp; int count = skb_queue_len(&pending), tmp;
...@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta) ...@@ -1127,7 +1140,12 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
buffered += tmp - count; buffered += tmp - count;
} }
ieee80211_add_pending_skbs_fn(local, &pending, clear_sta_ps_flags, sta); ieee80211_add_pending_skbs(local, &pending);
clear_sta_flag(sta, WLAN_STA_PS_DRIVER);
clear_sta_flag(sta, WLAN_STA_PS_STA);
spin_unlock(&sta->ps_lock);
atomic_dec(&ps->num_sta_ps);
/* This station just woke up and isn't aware of our SMPS state */ /* This station just woke up and isn't aware of our SMPS state */
if (!ieee80211_smps_is_restrictive(sta->known_smps_mode, if (!ieee80211_smps_is_restrictive(sta->known_smps_mode,
......
...@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat { ...@@ -267,6 +267,7 @@ struct ieee80211_tx_latency_stat {
* @drv_unblock_wk: used for driver PS unblocking * @drv_unblock_wk: used for driver PS unblocking
* @listen_interval: listen interval of this station, when we're acting as AP * @listen_interval: listen interval of this station, when we're acting as AP
* @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly * @_flags: STA flags, see &enum ieee80211_sta_info_flags, do not use directly
* @ps_lock: used for powersave (when mac80211 is the AP) related locking
* @ps_tx_buf: buffers (per AC) of frames to transmit to this station * @ps_tx_buf: buffers (per AC) of frames to transmit to this station
* when it leaves power saving state or polls * when it leaves power saving state or polls
* @tx_filtered: buffers (per AC) of frames we already tried to * @tx_filtered: buffers (per AC) of frames we already tried to
...@@ -356,10 +357,8 @@ struct sta_info { ...@@ -356,10 +357,8 @@ struct sta_info {
/* use the accessors defined below */ /* use the accessors defined below */
unsigned long _flags; unsigned long _flags;
/* /* STA powersave lock and frame queues */
* STA powersave frame queues, no more than the internal spinlock_t ps_lock;
* locking required.
*/
struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS]; struct sk_buff_head ps_tx_buf[IEEE80211_NUM_ACS];
struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS]; struct sk_buff_head tx_filtered[IEEE80211_NUM_ACS];
unsigned long driver_buffered_tids; unsigned long driver_buffered_tids;
......
...@@ -478,6 +478,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) ...@@ -478,6 +478,20 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
sta->sta.addr, sta->sta.aid, ac); sta->sta.addr, sta->sta.aid, ac);
if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
purge_old_ps_buffers(tx->local); purge_old_ps_buffers(tx->local);
/* sync with ieee80211_sta_ps_deliver_wakeup */
spin_lock(&sta->ps_lock);
/*
* STA woke up the meantime and all the frames on ps_tx_buf have
* been queued to pending queue. No reordering can happen, go
* ahead and Tx the packet.
*/
if (!test_sta_flag(sta, WLAN_STA_PS_STA) &&
!test_sta_flag(sta, WLAN_STA_PS_DRIVER)) {
spin_unlock(&sta->ps_lock);
return TX_CONTINUE;
}
if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) { if (skb_queue_len(&sta->ps_tx_buf[ac]) >= STA_MAX_TX_BUFFER) {
struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]); struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf[ac]);
ps_dbg(tx->sdata, ps_dbg(tx->sdata,
...@@ -492,6 +506,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) ...@@ -492,6 +506,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING; info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS; info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb); skb_queue_tail(&sta->ps_tx_buf[ac], tx->skb);
spin_unlock(&sta->ps_lock);
if (!timer_pending(&local->sta_cleanup)) if (!timer_pending(&local->sta_cleanup))
mod_timer(&local->sta_cleanup, mod_timer(&local->sta_cleanup,
......
...@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local, ...@@ -435,9 +435,8 @@ void ieee80211_add_pending_skb(struct ieee80211_local *local,
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
} }
void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, void ieee80211_add_pending_skbs(struct ieee80211_local *local,
struct sk_buff_head *skbs, struct sk_buff_head *skbs)
void (*fn)(void *data), void *data)
{ {
struct ieee80211_hw *hw = &local->hw; struct ieee80211_hw *hw = &local->hw;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local, ...@@ -461,9 +460,6 @@ void ieee80211_add_pending_skbs_fn(struct ieee80211_local *local,
__skb_queue_tail(&local->pending[queue], skb); __skb_queue_tail(&local->pending[queue], skb);
} }
if (fn)
fn(data);
for (i = 0; i < hw->queues; i++) for (i = 0; i < hw->queues; i++)
__ieee80211_wake_queue(hw, i, __ieee80211_wake_queue(hw, i,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD); IEEE80211_QUEUE_STOP_REASON_SKB_ADD);
...@@ -1740,6 +1736,26 @@ int ieee80211_reconfig(struct ieee80211_local *local) ...@@ -1740,6 +1736,26 @@ int ieee80211_reconfig(struct ieee80211_local *local)
ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP, ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_SUSPEND); IEEE80211_QUEUE_STOP_REASON_SUSPEND);
/*
* Reconfigure sched scan if it was interrupted by FW restart or
* suspend.
*/
mutex_lock(&local->mtx);
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
lockdep_is_held(&local->mtx));
if (sched_scan_sdata && local->sched_scan_req)
/*
* Sched scan stopped, but we don't want to report it. Instead,
* we're trying to reschedule.
*/
if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
local->sched_scan_req))
sched_scan_stopped = true;
mutex_unlock(&local->mtx);
if (sched_scan_stopped)
cfg80211_sched_scan_stopped(local->hw.wiphy);
/* /*
* If this is for hw restart things are still running. * If this is for hw restart things are still running.
* We may want to change that later, however. * We may want to change that later, however.
...@@ -1768,26 +1784,6 @@ int ieee80211_reconfig(struct ieee80211_local *local) ...@@ -1768,26 +1784,6 @@ int ieee80211_reconfig(struct ieee80211_local *local)
WARN_ON(1); WARN_ON(1);
#endif #endif
/*
* Reconfigure sched scan if it was interrupted by FW restart or
* suspend.
*/
mutex_lock(&local->mtx);
sched_scan_sdata = rcu_dereference_protected(local->sched_scan_sdata,
lockdep_is_held(&local->mtx));
if (sched_scan_sdata && local->sched_scan_req)
/*
* Sched scan stopped, but we don't want to report it. Instead,
* we're trying to reschedule.
*/
if (__ieee80211_request_sched_scan_start(sched_scan_sdata,
local->sched_scan_req))
sched_scan_stopped = true;
mutex_unlock(&local->mtx);
if (sched_scan_stopped)
cfg80211_sched_scan_stopped(local->hw.wiphy);
return 0; return 0;
} }
......
...@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata, ...@@ -154,6 +154,11 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
return IEEE80211_AC_BE; return IEEE80211_AC_BE;
} }
if (skb->protocol == sdata->control_port_protocol) {
skb->priority = 7;
return ieee80211_downgrade_queue(sdata, skb);
}
/* use the data classifier to determine what 802.1d tag the /* use the data classifier to determine what 802.1d tag the
* data frame has */ * data frame has */
rcu_read_lock(); rcu_read_lock();
......
...@@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regulatory_request *reg_request) ...@@ -1700,7 +1700,7 @@ static void reg_process_hint(struct regulatory_request *reg_request)
return; return;
case NL80211_REGDOM_SET_BY_USER: case NL80211_REGDOM_SET_BY_USER:
treatment = reg_process_hint_user(reg_request); treatment = reg_process_hint_user(reg_request);
if (treatment == REG_REQ_OK || if (treatment == REG_REQ_IGNORE ||
treatment == REG_REQ_ALREADY_SET) treatment == REG_REQ_ALREADY_SET)
return; return;
schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142)); schedule_delayed_work(&reg_timeout, msecs_to_jiffies(3142));
......
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