Commit 6d52563f authored by Johannes Berg's avatar Johannes Berg Committed by John W. Linville

cfg80211/mac80211: enable proper device_set_wakeup_enable handling

In WoWLAN, we only get the triggers when we actually get
to suspend. As a consequence, drivers currently don't
know that the device should enable wakeup. However, the
device_set_wakeup_enable() API is intended to be called
when the wakeup is enabled, not later when needed.

Add a new set_wakeup() call to cfg80211 and mac80211 to
allow drivers to properly call device_set_wakeup_enable.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent da951c24
...@@ -1344,6 +1344,9 @@ struct cfg80211_gtk_rekey_data { ...@@ -1344,6 +1344,9 @@ struct cfg80211_gtk_rekey_data {
* be %NULL or contain the enabled Wake-on-Wireless triggers that are * be %NULL or contain the enabled Wake-on-Wireless triggers that are
* configured for the device. * configured for the device.
* @resume: wiphy device needs to be resumed * @resume: wiphy device needs to be resumed
* @set_wakeup: Called when WoWLAN is enabled/disabled, use this callback
* to call device_set_wakeup_enable() to enable/disable wakeup from
* the device.
* *
* @add_virtual_intf: create a new virtual interface with the given name, * @add_virtual_intf: create a new virtual interface with the given name,
* must set the struct wireless_dev's iftype. Beware: You must create * must set the struct wireless_dev's iftype. Beware: You must create
...@@ -1515,6 +1518,7 @@ struct cfg80211_gtk_rekey_data { ...@@ -1515,6 +1518,7 @@ struct cfg80211_gtk_rekey_data {
struct cfg80211_ops { struct cfg80211_ops {
int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow); int (*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
int (*resume)(struct wiphy *wiphy); int (*resume)(struct wiphy *wiphy);
void (*set_wakeup)(struct wiphy *wiphy, bool enabled);
struct net_device * (*add_virtual_intf)(struct wiphy *wiphy, struct net_device * (*add_virtual_intf)(struct wiphy *wiphy,
char *name, char *name,
......
...@@ -2233,6 +2233,7 @@ struct ieee80211_ops { ...@@ -2233,6 +2233,7 @@ struct ieee80211_ops {
#ifdef CONFIG_PM #ifdef CONFIG_PM
int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan); int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
int (*resume)(struct ieee80211_hw *hw); int (*resume)(struct ieee80211_hw *hw);
void (*set_wakeup)(struct ieee80211_hw *hw, bool enabled);
#endif #endif
int (*add_interface)(struct ieee80211_hw *hw, int (*add_interface)(struct ieee80211_hw *hw,
struct ieee80211_vif *vif); struct ieee80211_vif *vif);
......
...@@ -2695,6 +2695,13 @@ ieee80211_wiphy_get_channel(struct wiphy *wiphy) ...@@ -2695,6 +2695,13 @@ ieee80211_wiphy_get_channel(struct wiphy *wiphy)
return local->oper_channel; return local->oper_channel;
} }
#ifdef CONFIG_PM
static void ieee80211_set_wakeup(struct wiphy *wiphy, bool enabled)
{
drv_set_wakeup(wiphy_priv(wiphy), enabled);
}
#endif
struct cfg80211_ops mac80211_config_ops = { struct cfg80211_ops mac80211_config_ops = {
.add_virtual_intf = ieee80211_add_iface, .add_virtual_intf = ieee80211_add_iface,
.del_virtual_intf = ieee80211_del_iface, .del_virtual_intf = ieee80211_del_iface,
...@@ -2763,4 +2770,7 @@ struct cfg80211_ops mac80211_config_ops = { ...@@ -2763,4 +2770,7 @@ struct cfg80211_ops mac80211_config_ops = {
.probe_client = ieee80211_probe_client, .probe_client = ieee80211_probe_client,
.get_channel = ieee80211_wiphy_get_channel, .get_channel = ieee80211_wiphy_get_channel,
.set_noack_map = ieee80211_set_noack_map, .set_noack_map = ieee80211_set_noack_map,
#ifdef CONFIG_PM
.set_wakeup = ieee80211_set_wakeup,
#endif
}; };
...@@ -91,6 +91,19 @@ static inline int drv_resume(struct ieee80211_local *local) ...@@ -91,6 +91,19 @@ static inline int drv_resume(struct ieee80211_local *local)
trace_drv_return_int(local, ret); trace_drv_return_int(local, ret);
return ret; return ret;
} }
static inline void drv_set_wakeup(struct ieee80211_local *local,
bool enabled)
{
might_sleep();
if (!local->ops->set_wakeup)
return;
trace_drv_set_wakeup(local, enabled);
local->ops->set_wakeup(&local->hw, enabled);
trace_drv_return_void(local);
}
#endif #endif
static inline int drv_add_interface(struct ieee80211_local *local, static inline int drv_add_interface(struct ieee80211_local *local,
......
...@@ -171,6 +171,20 @@ DEFINE_EVENT(local_only_evt, drv_resume, ...@@ -171,6 +171,20 @@ DEFINE_EVENT(local_only_evt, drv_resume,
TP_ARGS(local) TP_ARGS(local)
); );
TRACE_EVENT(drv_set_wakeup,
TP_PROTO(struct ieee80211_local *local, bool enabled),
TP_ARGS(local, enabled),
TP_STRUCT__entry(
LOCAL_ENTRY
__field(bool, enabled)
),
TP_fast_assign(
LOCAL_ASSIGN;
__entry->enabled = enabled;
),
TP_printk(LOCAL_PR_FMT " enabled:%d", LOCAL_PR_ARG, __entry->enabled)
);
DEFINE_EVENT(local_only_evt, drv_stop, DEFINE_EVENT(local_only_evt, drv_stop,
TP_PROTO(struct ieee80211_local *local), TP_PROTO(struct ieee80211_local *local),
TP_ARGS(local) TP_ARGS(local)
......
...@@ -708,6 +708,10 @@ void wiphy_unregister(struct wiphy *wiphy) ...@@ -708,6 +708,10 @@ void wiphy_unregister(struct wiphy *wiphy)
flush_work(&rdev->scan_done_wk); flush_work(&rdev->scan_done_wk);
cancel_work_sync(&rdev->conn_work); cancel_work_sync(&rdev->conn_work);
flush_work(&rdev->event_work); flush_work(&rdev->event_work);
if (rdev->wowlan && rdev->ops->set_wakeup)
rdev->ops->set_wakeup(&rdev->wiphy, false);
cfg80211_rdev_free_wowlan(rdev);
} }
EXPORT_SYMBOL(wiphy_unregister); EXPORT_SYMBOL(wiphy_unregister);
...@@ -720,7 +724,6 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev) ...@@ -720,7 +724,6 @@ void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
mutex_destroy(&rdev->sched_scan_mtx); mutex_destroy(&rdev->sched_scan_mtx);
list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list) list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
cfg80211_put_bss(&scan->pub); cfg80211_put_bss(&scan->pub);
cfg80211_rdev_free_wowlan(rdev);
kfree(rdev); kfree(rdev);
} }
......
...@@ -6014,6 +6014,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -6014,6 +6014,7 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
struct cfg80211_wowlan new_triggers = {}; struct cfg80211_wowlan new_triggers = {};
struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan; struct wiphy_wowlan_support *wowlan = &rdev->wiphy.wowlan;
int err, i; int err, i;
bool prev_enabled = rdev->wowlan;
if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns) if (!rdev->wiphy.wowlan.flags && !rdev->wiphy.wowlan.n_patterns)
return -EOPNOTSUPP; return -EOPNOTSUPP;
...@@ -6146,6 +6147,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info) ...@@ -6146,6 +6147,9 @@ static int nl80211_set_wowlan(struct sk_buff *skb, struct genl_info *info)
rdev->wowlan = NULL; rdev->wowlan = NULL;
} }
if (rdev->ops->set_wakeup && prev_enabled != !!rdev->wowlan)
rdev->ops->set_wakeup(&rdev->wiphy, rdev->wowlan);
return 0; return 0;
error: error:
for (i = 0; i < new_triggers.n_patterns; i++) for (i = 0; i < new_triggers.n_patterns; i++)
......
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