Commit 56cfb8ce authored by Johannes Berg's avatar Johannes Berg

wifi: cfg80211: add flush functions for wiphy work

There may be sometimes reasons to actually run the work
if it's pending, add flush functions for both regular and
delayed wiphy work that will do this.
Signed-off-by: default avatarJohannes Berg <johannes.berg@intel.com>
parent 7483a214
...@@ -5826,6 +5826,16 @@ void wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *work); ...@@ -5826,6 +5826,16 @@ void wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *work);
*/ */
void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work); void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work);
/**
* wiphy_work_flush - flush previously queued work
* @wiphy: the wiphy, for debug purposes
* @work: the work to flush, this can be %NULL to flush all work
*
* Flush the work (i.e. run it if pending). This must be called
* under the wiphy mutex acquired by wiphy_lock().
*/
void wiphy_work_flush(struct wiphy *wiphy, struct wiphy_work *work);
struct wiphy_delayed_work { struct wiphy_delayed_work {
struct wiphy_work work; struct wiphy_work work;
struct wiphy *wiphy; struct wiphy *wiphy;
...@@ -5869,6 +5879,17 @@ void wiphy_delayed_work_queue(struct wiphy *wiphy, ...@@ -5869,6 +5879,17 @@ void wiphy_delayed_work_queue(struct wiphy *wiphy,
void wiphy_delayed_work_cancel(struct wiphy *wiphy, void wiphy_delayed_work_cancel(struct wiphy *wiphy,
struct wiphy_delayed_work *dwork); struct wiphy_delayed_work *dwork);
/**
* wiphy_delayed work_flush - flush previously queued delayed work
* @wiphy: the wiphy, for debug purposes
* @work: the work to flush
*
* Flush the work (i.e. run it if pending). This must be called
* under the wiphy mutex acquired by wiphy_lock().
*/
void wiphy_delayed_work_flush(struct wiphy *wiphy,
struct wiphy_delayed_work *dwork);
/** /**
* struct wireless_dev - wireless device state * struct wireless_dev - wireless device state
* *
......
...@@ -1049,7 +1049,8 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy) ...@@ -1049,7 +1049,8 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy)
} }
EXPORT_SYMBOL(wiphy_rfkill_start_polling); EXPORT_SYMBOL(wiphy_rfkill_start_polling);
void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev) void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev,
struct wiphy_work *end)
{ {
unsigned int runaway_limit = 100; unsigned int runaway_limit = 100;
unsigned long flags; unsigned long flags;
...@@ -1068,6 +1069,10 @@ void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev) ...@@ -1068,6 +1069,10 @@ void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev)
wk->func(&rdev->wiphy, wk); wk->func(&rdev->wiphy, wk);
spin_lock_irqsave(&rdev->wiphy_work_lock, flags); spin_lock_irqsave(&rdev->wiphy_work_lock, flags);
if (wk == end)
break;
if (WARN_ON(--runaway_limit == 0)) if (WARN_ON(--runaway_limit == 0))
INIT_LIST_HEAD(&rdev->wiphy_work_list); INIT_LIST_HEAD(&rdev->wiphy_work_list);
} }
...@@ -1118,7 +1123,7 @@ void wiphy_unregister(struct wiphy *wiphy) ...@@ -1118,7 +1123,7 @@ void wiphy_unregister(struct wiphy *wiphy)
#endif #endif
/* surely nothing is reachable now, clean up work */ /* surely nothing is reachable now, clean up work */
cfg80211_process_wiphy_works(rdev); cfg80211_process_wiphy_works(rdev, NULL);
wiphy_unlock(&rdev->wiphy); wiphy_unlock(&rdev->wiphy);
rtnl_unlock(); rtnl_unlock();
...@@ -1640,6 +1645,21 @@ void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work) ...@@ -1640,6 +1645,21 @@ void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work)
} }
EXPORT_SYMBOL_GPL(wiphy_work_cancel); EXPORT_SYMBOL_GPL(wiphy_work_cancel);
void wiphy_work_flush(struct wiphy *wiphy, struct wiphy_work *work)
{
struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
unsigned long flags;
bool run;
spin_lock_irqsave(&rdev->wiphy_work_lock, flags);
run = !work || !list_empty(&work->entry);
spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags);
if (run)
cfg80211_process_wiphy_works(rdev, work);
}
EXPORT_SYMBOL_GPL(wiphy_work_flush);
void wiphy_delayed_work_timer(struct timer_list *t) void wiphy_delayed_work_timer(struct timer_list *t)
{ {
struct wiphy_delayed_work *dwork = from_timer(dwork, t, timer); struct wiphy_delayed_work *dwork = from_timer(dwork, t, timer);
...@@ -1672,6 +1692,16 @@ void wiphy_delayed_work_cancel(struct wiphy *wiphy, ...@@ -1672,6 +1692,16 @@ void wiphy_delayed_work_cancel(struct wiphy *wiphy,
} }
EXPORT_SYMBOL_GPL(wiphy_delayed_work_cancel); EXPORT_SYMBOL_GPL(wiphy_delayed_work_cancel);
void wiphy_delayed_work_flush(struct wiphy *wiphy,
struct wiphy_delayed_work *dwork)
{
lockdep_assert_held(&wiphy->mtx);
del_timer_sync(&dwork->timer);
wiphy_work_flush(wiphy, &dwork->work);
}
EXPORT_SYMBOL_GPL(wiphy_delayed_work_flush);
static int __init cfg80211_init(void) static int __init cfg80211_init(void)
{ {
int err; int err;
......
...@@ -469,7 +469,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev, ...@@ -469,7 +469,8 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
struct net_device *dev, enum nl80211_iftype ntype, struct net_device *dev, enum nl80211_iftype ntype,
struct vif_params *params); struct vif_params *params);
void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev); void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev); void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev,
struct wiphy_work *end);
void cfg80211_process_wdev_events(struct wireless_dev *wdev); void cfg80211_process_wdev_events(struct wireless_dev *wdev);
bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range, bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,
......
...@@ -105,14 +105,14 @@ static int wiphy_suspend(struct device *dev) ...@@ -105,14 +105,14 @@ static int wiphy_suspend(struct device *dev)
cfg80211_leave_all(rdev); cfg80211_leave_all(rdev);
cfg80211_process_rdev_events(rdev); cfg80211_process_rdev_events(rdev);
} }
cfg80211_process_wiphy_works(rdev); cfg80211_process_wiphy_works(rdev, NULL);
if (rdev->ops->suspend) if (rdev->ops->suspend)
ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config); ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config);
if (ret == 1) { if (ret == 1) {
/* Driver refuse to configure wowlan */ /* Driver refuse to configure wowlan */
cfg80211_leave_all(rdev); cfg80211_leave_all(rdev);
cfg80211_process_rdev_events(rdev); cfg80211_process_rdev_events(rdev);
cfg80211_process_wiphy_works(rdev); cfg80211_process_wiphy_works(rdev, NULL);
ret = rdev_suspend(rdev, NULL); ret = rdev_suspend(rdev, NULL);
} }
if (ret == 0) if (ret == 0)
......
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