[RFC PATCH 1/8] mac80211: Move dynamic PS data out of common code

Seth Forshee
2013-12-16T22:01:05Z

The timers and work structs for dynamic powersave are used only
for managed interfaces, so move them to ieee80211_if_managed and
deal with them only in sections of code specifically dealing with
managed mode interfaces.

Signed-off-by: Seth Forshee <seth.forshee@canonical.com>
---
net/mac80211/ieee80211_i.h | 11 +++---
net/mac80211/iface.c | 3 --
net/mac80211/main.c | 7 ----
net/mac80211/mlme.c | 89 +++++++++++++++++++++++++++++++---------------
net/mac80211/offchannel.c | 6 ++--
net/mac80211/pm.c | 17 +++++----
net/mac80211/rx.c | 10 +-----
net/mac80211/status.c | 4 +--
net/mac80211/tx.c | 4 +--
net/mac80211/util.c | 11 ++++++
10 files changed, 94 insertions(+), 68 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index ed5bf8b..785d1b8 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -387,10 +387,13 @@ struct ieee80211_if_managed {
struct timer_list conn_mon_timer;
struct timer_list bcn_mon_timer;
struct timer_list chswitch_timer;
+ struct timer_list dynamic_ps_timer;
struct work_struct monitor_work;
struct work_struct chswitch_work;
struct work_struct beacon_connection_loss_work;
struct work_struct csa_connection_drop_work;
+ struct work_struct dynamic_ps_enable_work;
+ struct work_struct dynamic_ps_disable_work;

unsigned long beacon_timeout;
unsigned long probe_timeout;
@@ -1188,9 +1191,6 @@ struct ieee80211_local {
* interface (and monitors) in PS, this then points there.
*/
struct ieee80211_sub_if_data *ps_sdata;
- struct work_struct dynamic_ps_enable_work;
- struct work_struct dynamic_ps_disable_work;
- struct timer_list dynamic_ps_timer;
struct notifier_block network_latency_notifier;
struct notifier_block ifa_notifier;
struct notifier_block ifa6_notifier;
@@ -1363,6 +1363,7 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency);
void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata);
+void ieee80211_mgd_notify_rx(struct ieee80211_rx_data *rx);
int ieee80211_max_network_latency(struct notifier_block *nb,
unsigned long data, void *dummy);
int ieee80211_set_arp_filter(struct ieee80211_sub_if_data *sdata);
@@ -1594,6 +1595,7 @@ static inline int __ieee80211_resume(struct ieee80211_hw *hw)
extern void *mac80211_wiphy_privid; /* for wiphy privid */
u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
enum nl80211_iftype type);
+void ieee80211_notify_rx(struct ieee80211_rx_data *rx);
int ieee80211_frame_duration(enum ieee80211_band band, size_t len,
int rate, int erp, int short_preamble,
int shift);
@@ -1654,9 +1656,6 @@ static inline void ieee802_11_parse_elems(const u8 *start, size_t len,
ieee802_11_parse_elems_crc(start, len, action, elems, 0, 0);
}

-void ieee80211_dynamic_ps_enable_work(struct work_struct *work);
-void ieee80211_dynamic_ps_disable_work(struct work_struct *work);
-void ieee80211_dynamic_ps_timer(unsigned long data);
void ieee80211_send_nullfunc(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
int powersave);
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 7aa9f9d..784b651 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -816,9 +816,6 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
netif_addr_unlock_bh(sdata->dev);
}

- del_timer_sync(&local->dynamic_ps_timer);
- cancel_work_sync(&local->dynamic_ps_enable_work);
-
cancel_work_sync(&sdata->recalc_smps);
sdata->vif.csa_active = false;
cancel_work_sync(&sdata->csa_finalize_work);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index fa34cd2..4ab607c 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -614,13 +614,6 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
INIT_WORK(&local->reconfig_filter, ieee80211_reconfig_filter);
local->smps_mode = IEEE80211_SMPS_OFF;

- INIT_WORK(&local->dynamic_ps_enable_work,
- ieee80211_dynamic_ps_enable_work);
- INIT_WORK(&local->dynamic_ps_disable_work,
- ieee80211_dynamic_ps_disable_work);
- setup_timer(&local->dynamic_ps_timer,
- ieee80211_dynamic_ps_timer, (unsigned long) local);
-
INIT_WORK(&local->sched_scan_stopped_work,
ieee80211_sched_scan_stopped_work);

diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 900ead3..4ec8c0a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -1139,6 +1139,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata)
{
struct ieee80211_conf *conf = &local->hw.conf;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

/*
* If we are scanning right now then the parameters will
@@ -1149,7 +1150,7 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,

if (conf->dynamic_ps_timeout > 0 &&
!(local->hw.flags & IEEE80211_HW_SUPPORTS_DYNAMIC_PS)) {
- mod_timer(&local->dynamic_ps_timer, jiffies +
+ mod_timer(&ifmgd->dynamic_ps_timer, jiffies +
msecs_to_jiffies(conf->dynamic_ps_timeout));
} else {
if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK)
@@ -1164,17 +1165,19 @@ static void ieee80211_enable_ps(struct ieee80211_local *local,
}
}

-static void ieee80211_change_ps(struct ieee80211_local *local)
+static void ieee80211_change_ps(struct ieee80211_sub_if_data *sdata, bool ps_enable)
{
+ struct ieee80211_local *local = sdata->local;
struct ieee80211_conf *conf = &local->hw.conf;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;

- if (local->ps_sdata) {
- ieee80211_enable_ps(local, local->ps_sdata);
+ if (ps_enable) {
+ ieee80211_enable_ps(local, sdata);
} else if (conf->flags & IEEE80211_CONF_PS) {
conf->flags &= ~IEEE80211_CONF_PS;
ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS);
- del_timer_sync(&local->dynamic_ps_timer);
- cancel_work_sync(&local->dynamic_ps_enable_work);
+ del_timer_sync(&ifmgd->dynamic_ps_timer);
+ cancel_work_sync(&ifmgd->dynamic_ps_enable_work);
}
}

@@ -1211,7 +1214,7 @@ static bool ieee80211_powersave_allowed(struct ieee80211_sub_if_data *sdata)
/* need to hold RTNL or interface lock */
void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
{
- struct ieee80211_sub_if_data *sdata, *found = NULL;
+ struct ieee80211_sub_if_data *sdata, *old_ps_sdata, *found = NULL;
int count = 0;
int timeout;

@@ -1220,6 +1223,8 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
return;
}

+ old_ps_sdata = local->ps_sdata;
+
list_for_each_entry(sdata, &local->interfaces, list) {
if (!ieee80211_sdata_running(sdata))
continue;
@@ -1284,7 +1289,10 @@ void ieee80211_recalc_ps(struct ieee80211_local *local, s32 latency)
local->ps_sdata = NULL;
}

- ieee80211_change_ps(local);
+ if (local->ps_sdata)
+ ieee80211_change_ps(local->ps_sdata, true);
+ else if (old_ps_sdata)
+ ieee80211_change_ps(old_ps_sdata, false);
}

void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata)
@@ -1297,11 +1305,12 @@ void ieee80211_recalc_ps_vif(struct ieee80211_sub_if_data *sdata)
}
}

-void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
+static void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
{
- struct ieee80211_local *local =
- container_of(work, struct ieee80211_local,
- dynamic_ps_disable_work);
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.dynamic_ps_disable_work);
+ struct ieee80211_local *local = sdata->local;

if (local->hw.conf.flags & IEEE80211_CONF_PS) {
local->hw.conf.flags &= ~IEEE80211_CONF_PS;
@@ -1313,29 +1322,27 @@ void ieee80211_dynamic_ps_disable_work(struct work_struct *work)
IEEE80211_QUEUE_STOP_REASON_PS);
}

-void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
+static void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
{
- struct ieee80211_local *local =
- container_of(work, struct ieee80211_local,
- dynamic_ps_enable_work);
- struct ieee80211_sub_if_data *sdata = local->ps_sdata;
- struct ieee80211_if_managed *ifmgd;
+ struct ieee80211_sub_if_data *sdata =
+ container_of(work, struct ieee80211_sub_if_data,
+ u.mgd.dynamic_ps_enable_work);
+ struct ieee80211_local *local = sdata->local;
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
unsigned long flags;
int q;

/* can only happen when PS was just disabled anyway */
- if (!sdata)
+ if (!local->ps_sdata)
return;

- ifmgd = &sdata->u.mgd;
-
if (local->hw.conf.flags & IEEE80211_CONF_PS)
return;

if (local->hw.conf.dynamic_ps_timeout > 0) {
/* don't enter PS if TX frames are pending */
if (drv_tx_frames_pending(local)) {
- mod_timer(&local->dynamic_ps_timer, jiffies +
+ mod_timer(&ifmgd->dynamic_ps_timer, jiffies +
msecs_to_jiffies(
local->hw.conf.dynamic_ps_timeout));
return;
@@ -1351,7 +1358,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
if (local->queue_stop_reasons[q]) {
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags);
- mod_timer(&local->dynamic_ps_timer, jiffies +
+ mod_timer(&ifmgd->dynamic_ps_timer, jiffies +
msecs_to_jiffies(
local->hw.conf.dynamic_ps_timeout));
return;
@@ -1363,7 +1370,7 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
if ((local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) &&
!(ifmgd->flags & IEEE80211_STA_NULLFUNC_ACKED)) {
if (drv_tx_frames_pending(local)) {
- mod_timer(&local->dynamic_ps_timer, jiffies +
+ mod_timer(&ifmgd->dynamic_ps_timer, jiffies +
msecs_to_jiffies(
local->hw.conf.dynamic_ps_timeout));
} else {
@@ -1382,14 +1389,30 @@ void ieee80211_dynamic_ps_enable_work(struct work_struct *work)
}
}

-void ieee80211_dynamic_ps_timer(unsigned long data)
+static void ieee80211_dynamic_ps_timer(unsigned long data)
{
- struct ieee80211_local *local = (void *) data;
+ struct ieee80211_sub_if_data *sdata = (void *)data;
+ struct ieee80211_local *local = sdata->local;

if (local->quiescing || local->suspended)
return;

- ieee80211_queue_work(&local->hw, &local->dynamic_ps_enable_work);
+ ieee80211_queue_work(&local->hw, &sdata->u.mgd.dynamic_ps_enable_work);
+}
+
+void ieee80211_mgd_notify_rx(struct ieee80211_rx_data *rx)
+{
+ struct ieee80211_sub_if_data *sdata = rx->sdata;
+ struct ieee80211_local *local = rx->local;
+
+ if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
+ !is_multicast_ether_addr(
+ ((struct ethhdr *)rx->skb->data)->h_dest) &&
+ (!local->scanning &&
+ !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))) {
+ mod_timer(&sdata->u.mgd.dynamic_ps_timer, jiffies +
+ msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
+ }
}

void ieee80211_dfs_cac_timer_work(struct work_struct *work)
@@ -1719,8 +1742,8 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,

sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;

- del_timer_sync(&local->dynamic_ps_timer);
- cancel_work_sync(&local->dynamic_ps_enable_work);
+ del_timer_sync(&ifmgd->dynamic_ps_timer);
+ cancel_work_sync(&ifmgd->dynamic_ps_enable_work);

/* Disable ARP filtering */
if (sdata->vif.bss_conf.arp_addr_cnt)
@@ -3506,6 +3529,10 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
INIT_WORK(&ifmgd->csa_connection_drop_work,
ieee80211_csa_connection_drop_work);
INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work);
+ INIT_WORK(&ifmgd->dynamic_ps_enable_work,
+ ieee80211_dynamic_ps_enable_work);
+ INIT_WORK(&ifmgd->dynamic_ps_disable_work,
+ ieee80211_dynamic_ps_disable_work);
setup_timer(&ifmgd->timer, ieee80211_sta_timer,
(unsigned long) sdata);
setup_timer(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer,
@@ -3514,6 +3541,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
(unsigned long) sdata);
setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
(unsigned long) sdata);
+ setup_timer(&ifmgd->dynamic_ps_timer, ieee80211_dynamic_ps_timer,
+ (unsigned long) sdata);

ifmgd->flags = 0;
ifmgd->powersave = sdata->wdev.ps;
@@ -4361,6 +4390,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
cancel_work_sync(&ifmgd->request_smps_work);
cancel_work_sync(&ifmgd->csa_connection_drop_work);
cancel_work_sync(&ifmgd->chswitch_work);
+ cancel_work_sync(&ifmgd->dynamic_ps_enable_work);

sdata_lock(sdata);
if (ifmgd->assoc_data) {
@@ -4371,6 +4401,7 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
if (ifmgd->auth_data)
ieee80211_destroy_auth_data(sdata, false);
del_timer_sync(&ifmgd->timer);
+ del_timer_sync(&ifmgd->dynamic_ps_timer);
sdata_unlock(sdata);
}

diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 0c2a294..2049a0a 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -33,11 +33,11 @@ static void ieee80211_offchannel_ps_enable(struct ieee80211_sub_if_data *sdata)

/* FIXME: what to do when local->pspolling is true? */

- del_timer_sync(&local->dynamic_ps_timer);
+ del_timer_sync(&ifmgd->dynamic_ps_timer);
del_timer_sync(&ifmgd->bcn_mon_timer);
del_timer_sync(&ifmgd->conn_mon_timer);

- cancel_work_sync(&local->dynamic_ps_enable_work);
+ cancel_work_sync(&ifmgd->dynamic_ps_enable_work);

if (local->hw.conf.flags & IEEE80211_CONF_PS) {
local->offchannel_ps_enabled = true;
@@ -94,7 +94,7 @@ static void ieee80211_offchannel_ps_disable(struct ieee80211_sub_if_data *sdata)
* the AP that we are awake.
*/
ieee80211_send_nullfunc(local, sdata, 0);
- mod_timer(&local->dynamic_ps_timer, jiffies +
+ mod_timer(&sdata->u.mgd.dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
}

diff --git a/net/mac80211/pm.c b/net/mac80211/pm.c
index 3401262..894c497 100644
--- a/net/mac80211/pm.c
+++ b/net/mac80211/pm.c
@@ -52,13 +52,6 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
/* Don't try to run timers while suspended. */
del_timer_sync(&local->sta_cleanup);

- /*
- * Note that this particular timer doesn't need to be
- * restarted at resume.
- */
- cancel_work_sync(&local->dynamic_ps_enable_work);
- del_timer_sync(&local->dynamic_ps_timer);
-
local->wowlan = wowlan && local->open_count;
if (local->wowlan) {
int err = drv_suspend(local, wowlan);
@@ -106,6 +99,16 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
sdata->vif.type == NL80211_IFTYPE_MONITOR)
continue;

+ if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+ struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+ /*
+ * Note that this particular timer doesn't need to be
+ * restarted at resume.
+ */
+ cancel_work_sync(&ifmgd->dynamic_ps_enable_work);
+ del_timer_sync(&ifmgd->dynamic_ps_timer);
+ }
+
drv_remove_interface(local, sdata);
}

diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 2dfa755..5707566 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2212,7 +2212,6 @@ static ieee80211_rx_result debug_noinline
ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
{
struct ieee80211_sub_if_data *sdata = rx->sdata;
- struct ieee80211_local *local = rx->local;
struct net_device *dev = sdata->dev;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
__le16 fc = hdr->frame_control;
@@ -2258,14 +2257,7 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
dev->stats.rx_packets++;
dev->stats.rx_bytes += rx->skb->len;

- if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
- !is_multicast_ether_addr(
- ((struct ethhdr *)rx->skb->data)->h_dest) &&
- (!local->scanning &&
- !test_bit(SDATA_STATE_OFFCHANNEL, &sdata->state))) {
- mod_timer(&local->dynamic_ps_timer, jiffies +
- msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
- }
+ ieee80211_notify_rx(rx);

ieee80211_deliver_skb(rx);

diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 1ee85c4..3298fe9 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -740,8 +740,8 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
local->ps_sdata->u.mgd.flags |=
IEEE80211_STA_NULLFUNC_ACKED;
} else
- mod_timer(&local->dynamic_ps_timer, jiffies +
- msecs_to_jiffies(10));
+ mod_timer(&local->ps_sdata->u.mgd.dynamic_ps_timer,
+ jiffies + msecs_to_jiffies(10));
}

ieee80211_report_used_skb(local, skb, false);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 6d59e21..0ffc2066 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -253,14 +253,14 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
IEEE80211_QUEUE_STOP_REASON_PS);
ifmgd->flags &= ~IEEE80211_STA_NULLFUNC_ACKED;
ieee80211_queue_work(&local->hw,
- &local->dynamic_ps_disable_work);
+ &ifmgd->dynamic_ps_disable_work);
}

/* Don't restart the timer if we're not disassociated */
if (!ifmgd->associated)
return TX_CONTINUE;

- mod_timer(&local->dynamic_ps_timer, jiffies +
+ mod_timer(&ifmgd->dynamic_ps_timer, jiffies +
msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));

return TX_CONTINUE;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 875e172..010cd2c 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -95,6 +95,17 @@ u8 *ieee80211_get_bssid(struct ieee80211_hdr *hdr, size_t len,
return NULL;
}

+void ieee80211_notify_rx(struct ieee80211_rx_data *rx)
+{
+ switch(rx->sdata->vif.type) {
+ case NL80211_IFTYPE_MONITOR:
+ ieee80211_mgd_notify_rx(rx);
+ break;
+ default:
+ break;
+ }
+}
+
void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx)
{
struct sk_buff *skb;
--
1.8.3.2